[Downloaded 11-Jun-2002] What is JDOM? JDOM is, quite simply, a Java representation of an XML document. JDOM provides a way to represent that document for easy and efficient reading, manipulation, and writing. It has a straightforward API, is a lightweight and fast, and is optimized for the Java programmer. It's an alternative to DOM and SAX, although it integrates well with both DOM and SAX. What is JDOM not? JDOM is not a wrapper for the W3C's DOM, or another version of DOM. JDOM is a Java-based "document object model" for XML files. JDOM serves the same purpose as DOM, but is easier to use. JDOM is not an XML parser, like Xerces or Crimson. It is a document object model that uses XML parsers to build documents. JDOM's SAXBuilder class for example uses the SAX events generated by an XML parser to build a JDOM tree. The default XML parser used by JDOM is the JAXP-selected parser, but JDOM can use nearly any parser. Is JDOM an acronym? Nope. Just like JDBC is not officially an acronym, neither is JDOM. This ensures we comply with Sun's trademark policies as explained at [14]http://www.sun.com/policies/trademarks. What is the JDOM license? JDOM is available under an Apache-style open source license, with the acknowledgment clause removed. This license is among the least restrictive license available, enabling developers to use JDOM in creating new products without requiring them to release their own products as open source. This is the license model used by the Apache Project, which created the Apache server. The license is available at the top of every source file and in LICENSE.txt in the root of the distribution, or you can view it using CVSweb at [15]http://cvs.jdom.org/cgi-bin/viewcvs.cgi/jdom/LICENSE.txt. Where can I get JDOM? JDOM is available in binary and source form from [16]http://www.jdom.org. What is the JDOM Philosophy? JDOM has been and will continue to be developed with this philosophy: * JDOM should be straightforward for Java programmers. * JDOM should support easy and efficient document modification. * JDOM should hide the complexities of XML wherever possible, while remaining true to the XML specification. * JDOM should integrate with DOM and SAX. * JDOM should be lightweight and fast. * JDOM should solve 80% (or more) of Java/XML problems with 20% (or less) of the effort Why is the JDOM API defined in terms of concrete classes rather than interfaces? This issue has been discussed several times on the JDOM mailing list, with several people on both sides. In general, many people feel that a class-based API is better when subclassing is not needed, while an interface-based API is better when subclassing is needed. However, either system can be used in either case. Jason Hunter summarizes the arguments against an interface-based API for JDOM: With interfaces everything becomes a factory, elements have to be 'imported' into new documents instead of just added, features like long-term serialization cannot be guaranteed, and the list goes on. We started with interfaces actually. During our pre-release review to some peers we received the feedback we should try concrete classes. We did, and the design was much better for it. Think about java.io.File as an analogy. There's a reason we say: File parent = new File(filepath); File child = new File(parent, "aaa.txt"); rather than FileSystem fs = FileSystem.getDefaultFileSystem(); File parent = fs.getFile(filepath); File child = fs.getFile(parent, "aaa.txt"); The former is simply easier and nicer to deal with. Another point to keep in mind is that anything that can be done with interfaces can be done with subclassing - the only penalty is possibly unused variables in the base class. For reference, the latest mailing list discussion on this topic started Nov. 30, 2000 with "Interfaces", and continued with "Interface-based JDOM" and "Announce: JDOMPlus". It would help to review this discussion before bringing this topic up on the mailing list. How does JDOM work with DOM and SAX? JDOM documents can be built from XML files, DOM trees, SAX events, or any other source. JDOM documents can be converted to XML files, DOM trees, SAX events, or any other destination. This ability proves useful, for example, when integrating with a program that expects SAX events. JDOM can parse an XML file, let the programmer easily and efficiently manipulate the document, then fire SAX events to the second program directly - no conversion to a serialized format is necessary. Was JDOM designed for Java 2? Yes, JDOM has been designed using the List and Map interfaces from the Java 2 Collections API. The Collections API provides JDOM with great power and flexibility through standard APIs. We may hear some ranting for the next three months about this, but we believe that this is better than hearing ranting starting three months from now about why we are still using the slow and weak Vector in our code! I tried to use JDOM and get an error like this: java.lang.NoSuchMethodError or java.lang.NoClassDefFoundError: org/xml/sax/SAXNotRecognizedException What's wrong? You need to ensure that the xerces.jar file supplied with the JDOM download is in your classpath before any other XML classes, such as those that come with JAXP or Crimson. These other XML libraries, as well as older versions of Apache Xerces, support DOM Level 1 and SAX 1.0, not the required DOM Level 2 and SAX 2.0. The result is an exception being thrown. Check your classpath, and try again. If the classpath looks OK, the problematic JAR might also be hiding in the system's standard extension directory (see the following). What do you mean "Standard extension directory"? The standard extension directory is a directory containing JAR files that is searched automatically by the Java runtime and compiler. If you've installed the JDK (not the just the JRE) you may well have two separate ext directories, one of which is used for compiling (typically somewhere like C:\jdk1.3\jre\lib\ext) and the other of which is used for running code (typically somewhere like C:\Program Files\JavaSoft\jre\1.3\lib\ext). The wrong JAR file in either directory can get in your way (though at different times). Furthermore, the right JAR file has to be in both directories. How do I avoid the DOM Level 1 problem in Visual Age for Java? When the WTE feature is added to the workspace, the project 'IBM XML Parser for Java' is added as well. This project contains old DOM Level 1 'org.w3c.*' interfaces. JDOM relies on DOM Level 2, and therefore conficts with this project. The solution is to do the following: 1. Change workspace owner to Administrator 2. Create open edition of the project 'IBM XML Parser for Java' 3. Delete all the packages that contain org.w3c.* interfaces 4. Version the project. 5. Create a new Project for DOM Level 2 parser such as Xerces 6. Import all Xerces classes including org.w3c.* interfaces (you can use a completly different project for those interfaces if you want to work with other parsers) 7. Version the Xerces project 8. Create a JDOM project and import jdom classes into it. Version the project (Contributed by Guy Nirpaz) How do I avoid the DOM Level 1 problem in WebSphere? WebSphere has the same issue with DOM Level 1 interfaces as VAJ above. The solution is to do one the following: * Put the path to xerces.jar (or other DOM Level 2 interfaces) in the variable 'com.ibm.ejs.sm.adminserver.classpath' in the file admin.config. This resides in $WAS_ROOT$/bin before all other variables. * or, if you run WAS $WAS_ROOT/bin/debug/adminserver.{bat|sh} add a line 'set WAS_CP=xerces.jar' (or other DOM Level 2 interfaces) before other set WAS_CP commands. * or, add JDOM to the application server CLASSPATH, using either the admin.cfg file or the administration console. (Contributed by Guy Nirpaz) Does JDOM work with JDK 1.1? Yes. Because JDOM currently has no ties to Java 2 other than the Collections APIs, it's possible for someone with JDK 1.1 plus the collections.jar (available from [17]http://java.sun.com/beans/infobus/#collections) to use JDOM. The only "gotcha" is that the collections.jar places the Collections classes in com.sun.java.util.collections so you'll need to run the special JDOM build scripts build11.bat and build11.sh that trigger an import line replace task as part of the build. These scripts are available in the current CVS tree and beginning with beta5. Are there any performance numbers? Not yet. JDOM is still really new! Only preliminary numbers have been taken, but they have been extremely promising. And JDOM hasn't been tuned yet! How does JDOM integrate with XSLT? There are many ways to do XSL transforms with JDOM. The most straightforward way is to use the standard JAXP Transformer interface and the JDOMSource/JDOMResult classes found in the org.jdom.transform package. Look to the sample named XSLTransform for an example (jdom/samples). These classes were added after beta6, so you'll want to download the latest source from CVS. Is there XPath support in JDOM? XPath on JDOM is being developed by Bob McWhirter and others at [18]http://jaxen.org. The implementation is highly functional although not quite 100% complete. Bob's experience with implementing XPath on JDOM has helped shape and improve the JDOM core, and having XPath integration into the core is likely as soon as the implementation is complete. What features of XML are not fully handled by JDOM? Eventually we expect the answer to this question to be "None". Our goal is to achieve full XML spec compliance while also maintaining an API that is easy to learn and use, as well as fast and lightweight. We think it's definitely possible, especially with the great feedback and ideas from members of the jdom-interest mailing list. Here are the current outstanding issues: * Entities and entity references are an open area of development, and we are still experimenting with how Java developers want to handle entities while remaining true to the XML specification. Is JDOM thread safe? The core API has intentionally been left thread unsafe. In other words, there are no synchronized blocks within org.jdom. This decision makes sense because we expect the primary JDOM use cases to be: * Single thread reads an XML stream into JDOM and looks at it read only * Single thread reads an XML stream into JDOM and modifies it * Single thread reads an XML stream into JDOM and makes it available to a run time system for read only access The use case where a "Single thread reads an XML stream into JDOM and exposes it to multiple threads to modify its contents" is fairly rare. In that case, JDOM can still be made thread safe but the programmer simply has to perform their own synchronization, perhaps as synchronizing on the Document instance. Why does equals() only do a == check? In JDOM two objects are only equal if they're the exact same object. This lets a call like list.remove(elem) remove only the exact Element passed in, not any element that's equivalent. This's a very important distinction. Doing a full equals() on an Element would require recursing down the tree, and in general we believe it unlikely you'll want to know if this element and all its children are equivalent to another one. If you really do want to know you can write some comparison code yourself that checks only as much as you want to check (maybe the name/namespaces only) instead of doing a full recurse. Why is equals() declared final? The equals() methods are final for JDOM classes so that a subclass can't break the == behavior that's required for calls like list.remove(elem) to work as designed. How do I construct a Document from a String? You use standard Java IO library calls. Wrap the String with a StringReader and pass the reader to SAXBuilder: Document doc = builder.build(new StringReader(xml)); How do I remove an Element or other content? Use the methods on the List returned by getChildren() or getContent(). JDOM doesn't need special methods because the methods already exist in List. For example to remove an element from a list of children: List children = parent.getChildren(); children.remove(element); // given child children.remove(0); // first child Other methods on List provide options to remove all children, add a child at a given location, and so on. How do I move an Element from one place to another? There's no need for node "importing" like there is with DOM. Just remove the element from its current place, then add the element to its new place. The element's content (including its element children) will naturally "tag" along for the ride. You have to remove the element before adding it to its new place because elements may have only one parent returned by getParent(). newParent.addContent(elt.detach()); How do I copy an Element from one place to another? There's no need for node "importing" like there is with DOM. Just clone the element being copied and add its clone in its new place. You have to clone the element before adding it to its new place because elements may have only one parent returned by getParent(). newParent.addContent((Element)elt.clone()); Can an element or attribute name contain a colon? The XML 1.0 specification specifically reserves the colon character for use with XML Namespaces. No other use is compliant with XML 1.0. Therefore JDOM does not allow you to create element and attribute names that contain colons except when using namespaces. Furthermore, because of the way namespaces are implemented in JDOM, you cannot simply create an Element or Attribute with a fully qualified name like svg:title. That is you cannot do this: Element e = new Element("svg:title"); Instead you must split the two parts into a Namespace and a local name. This is the proper JDOM way to create an element in a namespace: Element e = new Element("title", "svg", "http://www.w3.org/2000/svg"); The first argument is the local name. The second argument is the prefix. The third argument is the namespace URI. The xml:lang and xml:space attributes are special cases that are allowed only because the XML 1.0 specification defined them before namespaces were current, and therefore a document that is not otherwise using namespaces may still want to include these two attributes. Why do I need to pass in a Namespace to getChild(), when the child element I'm looking for has no namespace declaration? Specifically, for this XML fragment: You need to use code like this: Namespace ns = Namespace.getNamespace("http://foo.com"); Element y = x.getChild("y", ns); Element z = y.getChild("z", ns); If I leave out the namespace from the second call to getChild(), it returns null. Why? JDOM works on the logical in-memory XML tree, not the textual representation on-disk. While the element z has no namespace declaration, it does have a namespace - the one inherited from its parent, which declares a default namespace (associated with the URI http://foo.com). According to the namespaces specification, the following XML fragment is identical in meaning to the previous one: The way that the JDOM API handles namespaces means that you can write code that works for both examples. Otherwise, you would need to have code that checked for each case separately. Similarly, if you were constructing (instead of reading) the XML in the first example above, you would need to write code like this: Namespace ns = Namespace.getNamespace("http://foo.com"); Element y = new Element("y", ns); x.addContent(y); Element z = new Element("z", ns); y.addContent(z); If you left out the Namespace instance from the constructor for the element z, you would have the following tree in-memory: Why do all new lines appear as \n, even on Windows? According to section 2.11 of the XML Recommendation, 2nd edition: To simplify the tasks of applications, an XML processor must normalize line breaks in parsed entities to #xA either by translating the two-character sequence #xD #xA and any #xD that is not followed by #xA to #xA on input before parsing, or by using some other method such that the characters passed to the application are the same as if it did this translation. In other words, this is exactly what's supposed to happen. Why does setText(" ") not do what I want? When you pass a string into a method like setText() JDOM assumes it's just that, a string, not a fragment of XML. For example, when you call: element.setText(" ") JDOM assumes you want to set the content to the string containing the six characters & # 1 6 0 ;. It does not parse it to attempt to understand it as XML first. Thus when you output the text using XMLOutputter it will naturally escape the special ampersand character and output &#160;. The solution is to pass regular Unicode characters to the setText() method or, if you have text data that you want to be interpreted as XML, pass it through an XML parser before it goes into JDOM. This is what the SAXBuilder and DOMBuilder classes do. When using an IDE debugger why do I see a strange ArrayIndexOutOfBoundsException? Some parsers (Xerces included) use this exception as part of their standard operating procedure, internally throwing and catching the exception. No code outside the library is meant see it. However, IDE debuggers are often configured to report any time this exception is thrown, and thus they expose the exception. It can be safely ignored. How do I add a PI or Comment before the root element? You must access the document content as a List. Either get the list and add content to its head, or set the list of content explicitly. doc.getContent().add(0, pi); or doc.setContent(listOfContent); How do I avoid getting an OutOfMemoryError? Most JVMs have an option to increase their maximum heap size, which is the maximum amount of memory the JVM can use for its objects. In the JDK 1.2 you can set your initial heap size to 32 Megs and maximum heap size to 64 Megs with the following command: java -Xms32m -Xmx64m SomeClass Of course, if your document is larger than available virtual memory, there's not much you can do short of helping us create a deferred-build document implementation. Why does my file encoding on output not match the encoding on input? The default character encoding used by XMLOutputter is UTF-8, a variable-length encoding that can represent all Unicode characters. This can be changed with a call to outputter.setEncoding(). It would be nice if XMLOutputter could default to the original encoding for a file, but unfortunately parsers don't indicate the original encoding. You have to set it programatically. This issue most often affects people with documents in the common ISO-8859-1 (Latin-1) encoding who use characters like ñ but aren't familiar with having to think about encodings. The tip to remember is that with these documents you must set the output encoding to ISO-8859-1, otherwise characters in the range 128-255 will be output using a double byte encoding in UTF-8 instead of the normal single byte encoding of ISO-8859-1. Why does passing a document through a socket sometimes hang the parser? The problem is that several XML parsers close the input stream when they read EOF (-1). This is true of Xerces, which is JDOM's default parser. It is also true of Crimson. Unfortunately, closing a SocketInputStream closes the underlying SocketImpl, setting the file descriptor to null. The socket's output stream is useless after this, so your application will be unable to send a response. To workaround, protect your socket's input stream with an InputStream wrapper that doesn't close the underlying stream (override the close() method), or read everything into a buffer before handing off to the JDOM builder: byte[] buf = new byte[length]; new DataInputStream(inputStream).readFully(buf); InputStream in = new ByteArrayInputStream(buf); (Contributed by Joseph Bowbeer) How do I keep the DTD from loading? Even when I turn off validation the parser tries to load the DTD file. Even when validation is turned off, an XML parser will by default load the external DTD file in order to parse the DTD for external entity declarations. Xerces has a feature to turn off this behavior named "http://apache.org/xml/features/nonvalidating/load-external-dtd" and if you know you're using Xerces you can set this feature on the builder. builder.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); If you're using another parser like Crimson, your best bet is to set up an EntityResolver that resolves the DTD without actually reading the separate file. import org.xml.sax.*; import java.io.*; public class NoOpEntityResolver implements EntityResolver { public InputSource resolveEntity(String publicId, String systemId) { return new InputSource(new StringBufferInputStream("")); } } Then in the builder... builder.setEntityResolver(new NoOpEntityResolver()); There is a downside to this approach. Any entities in the document will be resolved to the empty string, and will effectively disappear. If your document has entities, you need to setExpandEntities(false) code and ensure the EntityResolver only suppresses the DocType. How do I validate against a schema when using JDOM? JDOM doesn't have it's own parser; it uses standard parsers like Xerces to do the heavy lifting. If you want schema validation make sure you choose a parser that supports schemas. Xerces 2 is a good choice (get it from [19]http://xml.apache.org). You also need to use code JDOM Beta 8 or later. To specify the parser JDOM uses, you can either configure JAXP appropriately (since JDOM uses JAXP if it's available, see the end of this entry for details) or you can explicitly pass the name of the parser to the SAXBuilder constructor. For Xerces 2 the parser class is org.apache.xerces.parsers.SAXParser. You must also enable parser validation by passing "true" when creating a SAXBuilder. SAXBuilder builder = new SAXBuilder("org.apache.xerces.parsers.SAXParser", true); Next, you tell the parser (Xerces) you want to validate against a schema (or schemas), and you pass the parser information about those schema. Different parsers do this in different ways. In Xerces you do this by setting special 'features' and 'properties' of the parser. JDOM exposes these parser settings with the setFeature() and setProperty() methods on SAXBuilder. These pass-through methods were added after Beta 7, which is why you need Beta 8 or above. Schemas are enabled by setting the feature "http://apache.org/xml/features/validation/schema" to true. builder.setFeature( "http://apache.org/xml/features/validation/schema", true); Schema locations are given by setting the property "http://apache.org/xml/properties/schema/external-schemaLocation" to a list of whitespace separated name-value pairs. The 'name' is the namespace the schema is associated with, the 'value' is the location of the schema for that namespace. For example: builder.setProperty( "http://apache.org/xml/properties/schema/external-schemaLocation", "http://www.w3.org/2001/12/soap-envelope soap-envelope.xsd" + " " + "http://kevinj.develop.com/weblog/weblog.xsd weblog.xsd"); The above example shows how to validate against multiple schemas -- against the SOAP 1.2 schema where the namespace is http://www.w3.org/2001/12/soap-envelope and the and against a schema for namespace http://kevinj.develop.com/weblog/weblog.xsd. The files describing these schemas are in soap-envelope.xsd and weblog.xsd respectively. You can add as many of these name value pairs as necessary. The values themselves are URLs. The name value pairs follow the meaning given in the Schema recommendation ([20]http://www.w3.org/TR/xmlschema-1/#schema-loc). The complete code looks like this: SAXBuilder builder = new SAXBuilder("org.apache.xerces.parsers.SAXParser", true); builder.setFeature( "http://apache.org/xml/features/validation/schema", true); builder.setProperty( "http://apache.org/xml/properties/schema/external-schemaLocation", "http://www.w3.org/2001/12/soap-envelope soap-envelope.xsd" + " " + "http://kevinj.develop.com/weblog/weblog.xsd weblog.xsd"); Document doc = builder.build(xml); If you want to use JAXP to select the parser, you can skip specifying a class to the SAXBuilder constructor and instead set the system property "javax.xml.parsers.SAXParserFactory" to the value "org.apache.xerces.jaxp.SAXParserFactoryImpl". That tells JAXP to use Xerces' factory to build parsers. If you like, you can specify this property on the command line: java -Djavax.xml.parsers.SAXParserFactory= org.apache.xerces.jaxp.SAXParserFactoryImpl ... (Contributed by Kevin Jones) How can I perform in-memory validation against a DTD or Schema? Currently you can't do this, in JDOM or any other Java document object model API. However, this is something we'd like JDOM to support, and we have a volunteer who's working on it. JDOM ensures the document in memory is always well-formed. Can JDOM also ensure the document in memory is always valid? No, it's our current belief that it's better to expose a checkValid() type of call than to attempt constant validation checking. One reason is performance. A second reason is that you have a chicken-and-egg problem where for example an element needs exactly two child elements to be valid, but after adding either child the document will be in a temporarily invalid state. To work around this would require something like transactional modifications, and that's a lot of overhead for little gain. Why do I get an IndexOutOfBoundsException or ConcurrentModificationException on looping? Code like the following will throw an IndexOutOfBoundsException: List children = root.getChildren("foo"); int size = children.size(); for (int i = 0; i < size; i++) { Element child = (Element) children.get(i); child.detach(); otherRoot.addContent(child); } The reason is that the size of the list is pre-calculated but the size is reduced by one on each detach() call, causing the for loop to walk off the end of the list. The right way to loop is to use an Iterator. With an Iterator you don't have this problem, and it's faster as well. However, even with an Iterator, the following code throws a ConcurrentModificationException: List children = root.getChildren("foo"); Iterator itr = children.iterator(); while (itr.hasNext()) { Element child = (Element) itr.next(); child.detach(); otherRoot.addContent(child); } The reason is that the detach() call modifies the list of children at the same time the iterator is traversing the list, and that's a concurrent modification. The solution is to use the Iterator's remove() method instead of detach() in this situation: List children = root.getChildren("foo"); Iterator itr = children.iterator(); while (itr.hasNext()) { Element child = (Element) itr.next(); itr.remove(); otherRoot.addContent(child); } Is there an archive for the JDOM mailing lists? Yes, all the messages are available for your Web-based perusal. Below are the slick searchable archives: * [21]http://www.servlets.com/archive/servlet/SummarizeList?listName =jdom-interest * [22]http://www.servlets.com/archive/servlet/SummarizeList?listName =jdom-announce * [23]http://www.servlets.com/archive/servlet/SummarizeList?listName =jdom-commits There are additional archives at: * [24]http://lists.denveronline.net/lists/jdom-interest/ * [25]http://lists.denveronline.net/lists/jdom-announce/ * [26]http://lists.denveronline.net/lists/jdom-commits/ How do I unsubscribe from a mailing list? The URL to manage your list membership (including subscription) is attached at the bottom of every list message. It should be something like http://lists.denveronline.net/mailman/options/jdom-interest/youraddr@y ourhost.com. Make sure to replace "youraddr" with your address and "yourhost" with your host. For jdom-announce replace "interest" with "announce" in the URL. How do I post to the mailing list from multiple addresses? For spam protection, only members of the mailing list may post. To post from multiple accounts, subscribe each account and set the "Disable mail delivery" feature to "On" for all the extra accounts. You can set that feature at the URL given in the [27]previous answer. Should I ask general XML questions to Jason and Brett? No, they're busy enough already. But you can order Brett's book [28]Java and XML or one of the other XML introductory books like [29]XML Bible by Elliotte Rusty Harold (one of our prominent jdom-interest list members). When does JDOM 1.0 come out? Schedules are difficult to define because all developers are volunteers. Jason recently left his day job and has more time now to project manage, so things are picking up again after a slow-down in the summer and fall of 2001. The book Java and XML talks about JDOM 1.0; why the confusion? The book covers an early beta. Much has changed (for the better) since publication of the book. For the most accurate JDOM API trust the Javadocs, not the book. Brett was a little optimistic when writing the book. His 2nd Edition sets things straight. I have a question that isn't answered here. What do I do? First, you should [30]search the jdom-interest archives. For example, if you're using an Oracle parser and see an IllegalTargetException that smells fishy, you can search message bodies for "+oracle +illegaltargetexception" and you'll find discussion about the issue. The plus-signs mean those terms are required to exist in the message bodies returned. The searches are powerful and fast! If you don't find an answer in the archives, you can post to jdom-interest. If you think you found a bug, make sure you follow the following advice about bug reporting! How do I submit a bug report? If you believe you found a bug in JDOM, please follow this procedure: 1. Check the [31]TODO.txt file in the root of the distribution to see if it's a known issue. 2. Check if the problem occurs when using the [32]latest daily snapshot of JDOM. Odds are good the bug has already been fixed since the last beta. 3. Search the [33]jdom-interest archives as explained above. 4. If you don't find resolution with the latest snapshot, post to the [34]jdom-interest mailing list; make sure you're a subscriber first as only subscribers can post. 5. In the bug report, give as much information as possible -- the stack trace, a reproducible and short code example, the XML file causing problems. Make sure to state the version of JDOM used (which day's snapshot). 6. If you have a patch to fix the bug, please submit that along with the problem report. We love patches. Where can I learn more? JDOM API documentation, slides from the initial JDOM announcement, and other helpful resources can all be downloaded [35]here. References 14. http://www.sun.com/policies/trademarks 15. http://cvs.jdom.org/cgi-bin/viewcvs.cgi/jdom/LICENSE.txt 16. http://www.jdom.org/ 17. http://java.sun.com/beans/infobus/#collections 18. http://jaxen.org/ 19. http://xml.apache.org/ 20. http://www.w3.org/TR/xmlschema-1/#schema-loc 21. http://www.servlets.com/archive/servlet/SummarizeList?listName=jdom-interest 22. http://www.servlets.com/archive/servlet/SummarizeList?listName=jdom-announce 23. http://www.servlets.com/archive/servlet/SummarizeList?listName=jdom-commits 24. http://lists.denveronline.net/lists/jdom-interest/ 25. http://lists.denveronline.net/lists/jdom-announce/ 26. http://lists.denveronline.net/lists/jdom-commits/ 27. http://www.jdom.org/docs/faq.html#unsubscribe 28. http://www.amazon.com/exec/obidos/ASIN/0596000162/jasonhunter 29. http://www.amazon.com/exec/obidos/ASIN/0764532367/jasonhunter 30. http://www.servlets.com/archive/servlet/SearchList?listName=jdom-interest 31. http://cvs.jdom.org/cgi-bin/viewcvs.cgi/jdom/TODO.txt 32. http://cvs.jdom.org/ 33. http://www.servlets.com/archive/servlet/SearchList?listName=jdom-interest 34. http://www.jdom.org/involved/lists.html 35. http://www.jdom.org/downloads/docs.html