Desktop tool for browsing account info from EVE-Online
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Document.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. /*--
  2. $Id: Document.java,v 1.85 2007/11/10 05:28:58 jhunter Exp $
  3. Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions
  7. are met:
  8. 1. Redistributions of source code must retain the above copyright
  9. notice, this list of conditions, and the following disclaimer.
  10. 2. Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions, and the disclaimer that follows
  12. these conditions in the documentation and/or other materials
  13. provided with the distribution.
  14. 3. The name "JDOM" must not be used to endorse or promote products
  15. derived from this software without prior written permission. For
  16. written permission, please contact <request_AT_jdom_DOT_org>.
  17. 4. Products derived from this software may not be called "JDOM", nor
  18. may "JDOM" appear in their name, without prior written permission
  19. from the JDOM Project Management <request_AT_jdom_DOT_org>.
  20. In addition, we request (but do not require) that you include in the
  21. end-user documentation provided with the redistribution and/or in the
  22. software itself an acknowledgement equivalent to the following:
  23. "This product includes software developed by the
  24. JDOM Project (http://www.jdom.org/)."
  25. Alternatively, the acknowledgment may be graphical using the logos
  26. available at http://www.jdom.org/images/logos.
  27. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  28. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  29. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  30. DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
  31. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  32. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  33. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  34. USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  35. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  36. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  38. SUCH DAMAGE.
  39. This software consists of voluntary contributions made by many
  40. individuals on behalf of the JDOM Project and was originally
  41. created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
  42. Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
  43. on the JDOM Project, please see <http://www.jdom.org/>.
  44. */
  45. package org.jdom;
  46. import java.util.*;
  47. import org.jdom.filter.*;
  48. /**
  49. * An XML document. Methods allow access to the root element as well as the
  50. * {@link DocType} and other document-level information.
  51. *
  52. * @version $Revision: 1.85 $, $Date: 2007/11/10 05:28:58 $
  53. * @author Brett McLaughlin
  54. * @author Jason Hunter
  55. * @author Jools Enticknap
  56. * @author Bradley S. Huffman
  57. */
  58. public class Document implements Parent {
  59. private static final String CVS_ID =
  60. "@(#) $RCSfile: Document.java,v $ $Revision: 1.85 $ $Date: 2007/11/10 05:28:58 $ $Name: jdom_1_1 $";
  61. /**
  62. * This document's content including comments, PIs, a possible
  63. * DocType, and a root element.
  64. * Subclassers have to track content using their own
  65. * mechanism.
  66. */
  67. ContentList content = new ContentList(this);
  68. /**
  69. * See http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#baseURIs-Considerations
  70. */
  71. protected String baseURI = null;
  72. // Supports the setProperty/getProperty calls
  73. private HashMap propertyMap = null;
  74. /**
  75. * Creates a new empty document. A document must have a root element,
  76. * so this document will not be well-formed and accessor methods will
  77. * throw an IllegalStateException if this document is accessed before a
  78. * root element is added. This method is most useful for build tools.
  79. */
  80. public Document() {}
  81. /**
  82. * This will create a new <code>Document</code>,
  83. * with the supplied <code>{@link Element}</code>
  84. * as the root element, the supplied
  85. * <code>{@link DocType}</code> declaration, and the specified
  86. * base URI.
  87. *
  88. * @param rootElement <code>Element</code> for document root.
  89. * @param docType <code>DocType</code> declaration.
  90. * @param baseURI the URI from which this doucment was loaded.
  91. * @throws IllegalAddException if the given docType object
  92. * is already attached to a document or the given
  93. * rootElement already has a parent
  94. */
  95. public Document(Element rootElement, DocType docType, String baseURI) {
  96. if (rootElement != null) {
  97. setRootElement(rootElement);
  98. }
  99. if (docType != null) {
  100. setDocType(docType);
  101. }
  102. if (baseURI != null) {
  103. setBaseURI(baseURI);
  104. }
  105. }
  106. /**
  107. * This will create a new <code>Document</code>,
  108. * with the supplied <code>{@link Element}</code>
  109. * as the root element and the supplied
  110. * <code>{@link DocType}</code> declaration.
  111. *
  112. * @param rootElement <code>Element</code> for document root.
  113. * @param docType <code>DocType</code> declaration.
  114. * @throws IllegalAddException if the given DocType object
  115. * is already attached to a document or the given
  116. * rootElement already has a parent
  117. */
  118. public Document(Element rootElement, DocType docType) {
  119. this(rootElement, docType, null);
  120. }
  121. /**
  122. * This will create a new <code>Document</code>,
  123. * with the supplied <code>{@link Element}</code>
  124. * as the root element, and no <code>{@link DocType}</code>
  125. * declaration.
  126. *
  127. * @param rootElement <code>Element</code> for document root
  128. * @throws IllegalAddException if the given rootElement already has
  129. * a parent.
  130. */
  131. public Document(Element rootElement) {
  132. this(rootElement, null, null);
  133. }
  134. /**
  135. * This will create a new <code>Document</code>,
  136. * with the supplied list of content, and a
  137. * <code>{@link DocType}</code> declaration only if the content
  138. * contains a DocType instance. A null list is treated the
  139. * same as the no-arg constructor.
  140. *
  141. * @param content <code>List</code> of starter content
  142. * @throws IllegalAddException if the List contains more than
  143. * one Element or objects of illegal types.
  144. */
  145. public Document(List content) {
  146. setContent(content);
  147. }
  148. public int getContentSize() {
  149. return content.size();
  150. }
  151. public int indexOf(Content child) {
  152. return content.indexOf(child);
  153. }
  154. // /**
  155. // * Starting at the given index (inclusive), return the index of
  156. // * the first child matching the supplied filter, or -1
  157. // * if none is found.
  158. // *
  159. // * @return index of child, or -1 if none found.
  160. // */
  161. // private int indexOf(int start, Filter filter) {
  162. // int size = getContentSize();
  163. // for (int i = start; i < size; i++) {
  164. // if (filter.matches(getContent(i))) {
  165. // return i;
  166. // }
  167. // }
  168. // return -1;
  169. // }
  170. /**
  171. * This will return <code>true</code> if this document has a
  172. * root element, <code>false</code> otherwise.
  173. *
  174. * @return <code>true</code> if this document has a root element,
  175. * <code>false</code> otherwise.
  176. */
  177. public boolean hasRootElement() {
  178. return (content.indexOfFirstElement() < 0) ? false : true;
  179. }
  180. /**
  181. * This will return the root <code>Element</code>
  182. * for this <code>Document</code>
  183. *
  184. * @return <code>Element</code> - the document's root element
  185. * @throws IllegalStateException if the root element hasn't been set
  186. */
  187. public Element getRootElement() {
  188. int index = content.indexOfFirstElement();
  189. if (index < 0) {
  190. throw new IllegalStateException("Root element not set");
  191. }
  192. return (Element) content.get(index);
  193. }
  194. /**
  195. * This sets the root <code>{@link Element}</code> for the
  196. * <code>Document</code>. If the document already has a root
  197. * element, it is replaced.
  198. *
  199. * @param rootElement <code>Element</code> to be new root.
  200. * @return <code>Document</code> - modified Document.
  201. * @throws IllegalAddException if the given rootElement already has
  202. * a parent.
  203. */
  204. public Document setRootElement(Element rootElement) {
  205. int index = content.indexOfFirstElement();
  206. if (index < 0) {
  207. content.add(rootElement);
  208. }
  209. else {
  210. content.set(index, rootElement);
  211. }
  212. return this;
  213. }
  214. /**
  215. * Detach the root <code>{@link Element}</code> from this document.
  216. *
  217. * @return removed root <code>Element</code>
  218. */
  219. public Element detachRootElement() {
  220. int index = content.indexOfFirstElement();
  221. if (index < 0)
  222. return null;
  223. return (Element) removeContent(index);
  224. }
  225. /**
  226. * This will return the <code>{@link DocType}</code>
  227. * declaration for this <code>Document</code>, or
  228. * <code>null</code> if none exists.
  229. *
  230. * @return <code>DocType</code> - the DOCTYPE declaration.
  231. */
  232. public DocType getDocType() {
  233. int index = content.indexOfDocType();
  234. if (index < 0) {
  235. return null;
  236. }
  237. else {
  238. return (DocType) content.get(index);
  239. }
  240. }
  241. /**
  242. * This will set the <code>{@link DocType}</code>
  243. * declaration for this <code>Document</code>. Note
  244. * that a DocType can only be attached to one Document.
  245. * Attempting to set the DocType to a DocType object
  246. * that already belongs to a Document will result in an
  247. * IllegalAddException being thrown.
  248. *
  249. * @param docType <code>DocType</code> declaration.
  250. * @return object on which the method was invoked
  251. * @throws IllegalAddException if the given docType is
  252. * already attached to a Document.
  253. */
  254. public Document setDocType(DocType docType) {
  255. if (docType == null) {
  256. // Remove any existing doctype
  257. int docTypeIndex = content.indexOfDocType();
  258. if (docTypeIndex >= 0) content.remove(docTypeIndex);
  259. return this;
  260. }
  261. if (docType.getParent() != null) {
  262. throw new IllegalAddException(docType,
  263. "The DocType already is attached to a document");
  264. }
  265. // Add DocType to head if new, replace old otherwise
  266. int docTypeIndex = content.indexOfDocType();
  267. if (docTypeIndex < 0) {
  268. content.add(0, docType);
  269. }
  270. else {
  271. content.set(docTypeIndex, docType);
  272. }
  273. return this;
  274. }
  275. /**
  276. * Appends the child to the end of the content list.
  277. *
  278. * @param child child to append to end of content list
  279. * @return the document on which the method was called
  280. * @throws IllegalAddException if the given child already has a parent.
  281. */
  282. public Document addContent(Content child) {
  283. content.add(child);
  284. return this;
  285. }
  286. /**
  287. * Appends all children in the given collection to the end of
  288. * the content list. In event of an exception during add the
  289. * original content will be unchanged and the objects in the supplied
  290. * collection will be unaltered.
  291. *
  292. * @param c collection to append
  293. * @return the document on which the method was called
  294. * @throws IllegalAddException if any item in the collection
  295. * already has a parent or is of an illegal type.
  296. */
  297. public Document addContent(Collection c) {
  298. content.addAll(c);
  299. return this;
  300. }
  301. /**
  302. * Inserts the child into the content list at the given index.
  303. *
  304. * @param index location for adding the collection
  305. * @param child child to insert
  306. * @return the parent on which the method was called
  307. * @throws IndexOutOfBoundsException if index is negative or beyond
  308. * the current number of children
  309. * @throws IllegalAddException if the given child already has a parent.
  310. */
  311. public Document addContent(int index, Content child) {
  312. content.add(index, child);
  313. return this;
  314. }
  315. /**
  316. * Inserts the content in a collection into the content list
  317. * at the given index. In event of an exception the original content
  318. * will be unchanged and the objects in the supplied collection will be
  319. * unaltered.
  320. *
  321. * @param index location for adding the collection
  322. * @param c collection to insert
  323. * @return the parent on which the method was called
  324. * @throws IndexOutOfBoundsException if index is negative or beyond
  325. * the current number of children
  326. * @throws IllegalAddException if any item in the collection
  327. * already has a parent or is of an illegal type.
  328. */
  329. public Document addContent(int index, Collection c) {
  330. content.addAll(index, c);
  331. return this;
  332. }
  333. public List cloneContent() {
  334. int size = getContentSize();
  335. List list = new ArrayList(size);
  336. for (int i = 0; i < size; i++) {
  337. Content child = getContent(i);
  338. list.add(child.clone());
  339. }
  340. return list;
  341. }
  342. public Content getContent(int index) {
  343. return (Content) content.get(index);
  344. }
  345. // public Content getChild(Filter filter) {
  346. // int i = indexOf(0, filter);
  347. // return (i < 0) ? null : getContent(i);
  348. // }
  349. /**
  350. * This will return all content for the <code>Document</code>.
  351. * The returned list is "live" in document order and changes to it
  352. * affect the document's actual content.
  353. *
  354. * <p>
  355. * Sequential traversal through the List is best done with a Iterator
  356. * since the underlying implement of List.size() may require walking the
  357. * entire list.
  358. * </p>
  359. *
  360. * @return <code>List</code> - all Document content
  361. * @throws IllegalStateException if the root element hasn't been set
  362. */
  363. public List getContent() {
  364. if (!hasRootElement())
  365. throw new IllegalStateException("Root element not set");
  366. return content;
  367. }
  368. /**
  369. * Return a filtered view of this <code>Document</code>'s content.
  370. *
  371. * <p>
  372. * Sequential traversal through the List is best done with a Iterator
  373. * since the underlying implement of List.size() may require walking the
  374. * entire list.
  375. * </p>
  376. *
  377. * @param filter <code>Filter</code> to apply
  378. * @return <code>List</code> - filtered Document content
  379. * @throws IllegalStateException if the root element hasn't been set
  380. */
  381. public List getContent(Filter filter) {
  382. if (!hasRootElement())
  383. throw new IllegalStateException("Root element not set");
  384. return content.getView(filter);
  385. }
  386. /**
  387. * Removes all child content from this parent.
  388. *
  389. * @return list of the old children detached from this parent
  390. */
  391. public List removeContent() {
  392. List old = new ArrayList(content);
  393. content.clear();
  394. return old;
  395. }
  396. /**
  397. * Remove all child content from this parent matching the supplied filter.
  398. *
  399. * @param filter filter to select which content to remove
  400. * @return list of the old children detached from this parent
  401. */
  402. public List removeContent(Filter filter) {
  403. List old = new ArrayList();
  404. Iterator itr = content.getView(filter).iterator();
  405. while (itr.hasNext()) {
  406. Content child = (Content) itr.next();
  407. old.add(child);
  408. itr.remove();
  409. }
  410. return old;
  411. }
  412. /**
  413. * This sets the content of the <code>Document</code>. The supplied
  414. * List should contain only objects of type <code>Element</code>,
  415. * <code>Comment</code>, and <code>ProcessingInstruction</code>.
  416. *
  417. * <p>
  418. * When all objects in the supplied List are legal and before the new
  419. * content is added, all objects in the old content will have their
  420. * parentage set to null (no parent) and the old content list will be
  421. * cleared. This has the effect that any active list (previously obtained
  422. * with a call to {@link #getContent}) will also
  423. * change to reflect the new content. In addition, all objects in the
  424. * supplied List will have their parentage set to this document, but the
  425. * List itself will not be "live" and further removals and additions will
  426. * have no effect on this document content. If the user wants to continue
  427. * working with a "live" list, then a call to setContent should be
  428. * followed by a call to {@link #getContent} to
  429. * obtain a "live" version of the content.
  430. * </p>
  431. *
  432. * <p>
  433. * Passing a null or empty List clears the existing content.
  434. * </p>
  435. *
  436. * <p>
  437. * In event of an exception the original content will be unchanged and
  438. * the objects in the supplied content will be unaltered.
  439. * </p>
  440. *
  441. * @param newContent <code>List</code> of content to set
  442. * @return this document modified
  443. * @throws IllegalAddException if the List contains objects of
  444. * illegal types or with existing parentage.
  445. */
  446. public Document setContent(Collection newContent) {
  447. content.clearAndSet(newContent);
  448. return this;
  449. }
  450. /**
  451. *
  452. * <p>
  453. * Sets the effective URI from which this document was loaded,
  454. * and against which relative URLs in this document will be resolved.
  455. * </p>
  456. *
  457. * @param uri the base URI of this document
  458. */
  459. public final void setBaseURI(String uri) {
  460. this.baseURI = uri; // XXX We don't check the URI
  461. }
  462. /**
  463. * <p>
  464. * Returns the URI from which this document was loaded,
  465. * or null if this is not known.
  466. * </p>
  467. *
  468. * @return the base URI of this document
  469. */
  470. public final String getBaseURI() {
  471. return baseURI;
  472. }
  473. /*
  474. * Replace the current child the given index with the supplied child.
  475. * <p>
  476. * In event of an exception the original content will be unchanged and
  477. * the supplied child will be unaltered.
  478. * </p>
  479. *
  480. * @param index - index of child to replace.
  481. * @param child - child to add.
  482. * @throws IllegalAddException if the supplied child is already attached
  483. * or not legal content for this parent.
  484. * @throws IndexOutOfBoundsException if index is negative or greater
  485. * than the current number of children.
  486. */
  487. public Document setContent(int index, Content child) {
  488. content.set(index, child);
  489. return this;
  490. }
  491. /**
  492. * Replace the child at the given index whith the supplied
  493. * collection.
  494. * <p>
  495. * In event of an exception the original content will be unchanged and
  496. * the content in the supplied collection will be unaltered.
  497. * </p>
  498. *
  499. * @param index - index of child to replace.
  500. * @param collection - collection of content to add.
  501. * @return object on which the method was invoked
  502. * @throws IllegalAddException if the collection contains objects of
  503. * illegal types.
  504. * @throws IndexOutOfBoundsException if index is negative or greater
  505. * than the current number of children.
  506. */
  507. public Document setContent(int index, Collection collection) {
  508. content.remove(index);
  509. content.addAll(index, collection);
  510. return this;
  511. }
  512. public boolean removeContent(Content child) {
  513. return content.remove(child);
  514. }
  515. public Content removeContent(int index) {
  516. return (Content) content.remove(index);
  517. }
  518. /**
  519. * Set this document's content to be the supplied child.
  520. * <p>
  521. * If the supplied child is legal content for a Document and before
  522. * it is added, all content in the current content list will
  523. * be cleared and all current children will have their parentage set to
  524. * null.
  525. * <p>
  526. * This has the effect that any active list (previously obtained with
  527. * a call to one of the {@link #getContent} methods will also change
  528. * to reflect the new content. In addition, all content in the supplied
  529. * collection will have their parentage set to this Document. If the user
  530. * wants to continue working with a <b>"live"</b> list of this Document's
  531. * child, then a call to setContent should be followed by a call to one
  532. * of the {@link #getContent} methods to obtain a <b>"live"</b>
  533. * version of the children.
  534. * <p>
  535. * Passing a null child clears the existing content.
  536. * <p>
  537. * In event of an exception the original content will be unchanged and
  538. * the supplied child will be unaltered.
  539. *
  540. * @param child new content to replace existing content
  541. * @return the parent on which the method was called
  542. * @throws IllegalAddException if the supplied child is already attached
  543. * or not legal content for this parent
  544. */
  545. public Document setContent(Content child) {
  546. content.clear();
  547. content.add(child);
  548. return this;
  549. }
  550. /**
  551. * This returns a <code>String</code> representation of the
  552. * <code>Document</code>, suitable for debugging. If the XML
  553. * representation of the <code>Document</code> is desired,
  554. * {@link org.jdom.output.XMLOutputter#outputString(Document)}
  555. * should be used.
  556. *
  557. * @return <code>String</code> - information about the
  558. * <code>Document</code>
  559. */
  560. public String toString() {
  561. StringBuffer stringForm = new StringBuffer()
  562. .append("[Document: ");
  563. DocType docType = getDocType();
  564. if (docType != null) {
  565. stringForm.append(docType.toString())
  566. .append(", ");
  567. } else {
  568. stringForm.append(" No DOCTYPE declaration, ");
  569. }
  570. Element rootElement = getRootElement();
  571. if (rootElement != null) {
  572. stringForm.append("Root is ")
  573. .append(rootElement.toString());
  574. } else {
  575. stringForm.append(" No root element"); // shouldn't happen
  576. }
  577. stringForm.append("]");
  578. return stringForm.toString();
  579. }
  580. /**
  581. * This tests for equality of this <code>Document</code> to the supplied
  582. * <code>Object</code>.
  583. *
  584. * @param ob <code>Object</code> to compare to
  585. * @return <code>boolean</code> whether the <code>Document</code> is
  586. * equal to the supplied <code>Object</code>
  587. */
  588. public final boolean equals(Object ob) {
  589. return (ob == this);
  590. }
  591. /**
  592. * This returns the hash code for this <code>Document</code>.
  593. *
  594. * @return <code>int</code> hash code
  595. */
  596. public final int hashCode() {
  597. return super.hashCode();
  598. }
  599. /**
  600. * This will return a deep clone of this <code>Document</code>.
  601. *
  602. * @return <code>Object</code> clone of this <code>Document</code>
  603. */
  604. public Object clone() {
  605. Document doc = null;
  606. try {
  607. doc = (Document) super.clone();
  608. } catch (CloneNotSupportedException ce) {
  609. // Can't happen
  610. }
  611. // The clone has a reference to this object's content list, so
  612. // owerwrite with a empty list
  613. doc.content = new ContentList(doc);
  614. // Add the cloned content to clone
  615. for (int i = 0; i < content.size(); i++) {
  616. Object obj = content.get(i);
  617. if (obj instanceof Element) {
  618. Element element = (Element)((Element)obj).clone();
  619. doc.content.add(element);
  620. }
  621. else if (obj instanceof Comment) {
  622. Comment comment = (Comment)((Comment)obj).clone();
  623. doc.content.add(comment);
  624. }
  625. else if (obj instanceof ProcessingInstruction) {
  626. ProcessingInstruction pi = (ProcessingInstruction)
  627. ((ProcessingInstruction)obj).clone();
  628. doc.content.add(pi);
  629. }
  630. else if (obj instanceof DocType) {
  631. DocType dt = (DocType) ((DocType)obj).clone();
  632. doc.content.add(dt);
  633. }
  634. }
  635. return doc;
  636. }
  637. /**
  638. * Returns an iterator that walks over all descendants in document order.
  639. *
  640. * @return an iterator to walk descendants
  641. */
  642. public Iterator getDescendants() {
  643. return new DescendantIterator(this);
  644. }
  645. /**
  646. * Returns an iterator that walks over all descendants in document order
  647. * applying the Filter to return only elements that match the filter rule.
  648. * With filters you can match only Elements, only Comments, Elements or
  649. * Comments, only Elements with a given name and/or prefix, and so on.
  650. *
  651. * @param filter filter to select which descendants to see
  652. * @return an iterator to walk descendants within a filter
  653. */
  654. public Iterator getDescendants(Filter filter) {
  655. return new FilterIterator(new DescendantIterator(this), filter);
  656. }
  657. public Parent getParent() {
  658. return null; // documents never have parents
  659. }
  660. /**
  661. * @see org.jdom.Parent#getDocument()
  662. */
  663. public Document getDocument() {
  664. return this;
  665. }
  666. /**
  667. * Assigns an arbitrary object to be associated with this document under
  668. * the given "id" string. Null values are permitted. Strings beginning
  669. * with "http://www.jdom.org/ are reserved for JDOM use.
  670. *
  671. * @param id the id of the stored object
  672. * @param value the object to store
  673. */
  674. public void setProperty(String id, Object value) {
  675. if (propertyMap == null) {
  676. propertyMap = new HashMap();
  677. }
  678. propertyMap.put(id, value);
  679. }
  680. /**
  681. * Returns the object associated with this document under the given "id"
  682. * string, or null if there is no binding or if the binding explicitly
  683. * stored a null value.
  684. *
  685. * @param id the id of the stored object to return
  686. * @return the object associated with the given id
  687. */
  688. public Object getProperty(String id) {
  689. if (propertyMap == null) return null;
  690. return propertyMap.get(id);
  691. }
  692. }