tags:

views:

297

answers:

5

Although I know how to build a DOM the long, arduous way using the DOM API, I'd like to do something a bit better than that. Is there a nice, tidy way to build hierarchical documents with, say, an API that works something like Hibernate's Criteria API? So that I can chain calls together like this, for example:

Document doc = createDocumentSomehow ();
doc.createElement ("root").createElements (
    doc.newElement ("subnode")
        .createElement ("sub-subnode")
            .setText("some element text")
            .addAttribute ("attr-name","attr-value"),
    doc.newElement ("other_subnode"));

Ideally, this would result in XML like this:

<root>
  <subnode>
    <sub-subnode attr-name = "attr-value">some element text</sub-subnode>
  <other_subnode />
</root>

Basically, I'd like something where the Java itself isn't nearly four times longer than the document I'm generating. Does it exist?

+2  A: 

I highly recommend Elliotte Rusty Harold's XOM API.

It inter-operates with the W3C API, in that you can convert between XOM and DOM. The API guarantees a well-formed structure at all times. It's performant, robust, and follows consistent design principles.

erickson
+3  A: 

You definitely want to use JDom: http://www.jdom.org/docs/apidocs/ . It can be used as you described as many methods return a reference to this. Here is some code our teacher showed us for this XML document. Haven't tested it, but the teacher is great i believe in him:

<adressbuch aktualisiert="1.4.2008">
    <adresse>
        <vorname> Hugo </vorname>
        <nachname> Meier </nachname>
        <telefon typ="mobil">0160/987654 </telefon>
    </adresse>
</adressbuch>

Code:

new Document(
     new Element ("adressbuch")
     .setAttribute("aktualisiert", "1.4.2008")
     .addContent(
         (Element) new Element("adresse")
         .addContent(
                     (Element) new Element("vorname")
                     .addContent("Hugo"))
         .addContent(
                     (Element) new Element("nachname")
                     .addContent("Meier"))
         .addContent(
                     (Element) new Element("telefon")
                     .setAttribute("typ", "mobil")
                     .addContent("0160/987654"))));

From the API manual, it looks like the casts he did aren't necassary. Maybe he just did it for documentation purposes.

Johannes Schaub - litb
A: 

Try looking at the Quick Start guide for DOM4J. It makes getting the XML out pretty easy too. I've included a relevant snippet:

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class Foo {

    public Document createDocument() {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement( "root" );

        Element author1 = root.addElement( "author" )
            .addAttribute( "name", "James" )
            .addAttribute( "location", "UK" )
            .addText( "James Strachan" );

        Element author2 = root.addElement( "author" )
            .addAttribute( "name", "Bob" )
            .addAttribute( "location", "US" )
            .addText( "Bob McWhirter" );

        return document;
    }
}
Joe Liversedge
A: 

If you're willing to use Groovy inside your Java app, you can use the MarkupBuilder for Agile XML creation.

A: 

I don't know if touting your own project is against the culture here (didn't see anything in the FAQ), but here's my solution: https://sourceforge.net/projects/practicalxml/

public static void main(String[] argv)
throws Exception
{
    ElementNode root =
        element("albums",
            element("artist",
                attribute("name", "Anderson, Laurie"),
                element("album", text("Big Science")),
                element("album", text("Mister Heartbreak")),
                element("album", text("Strange Angels"))),
            element("artist",
                attribute("name", "Becker & Fagan"),
                element("album", text("The Collection"))),
            element("artist",
                attribute("name", "Fine Young Cannibals"),
                element("album", text("The Raw & The Cooked"))));

    System.out.println(root.toString(4));
}

At present this is still in pre-release mode, so if you're going to use it you'll have to download the SVN tarball and build yourself. Once I finish the parsing code, it will hit 1.0-SNAPSHOT, and stay there for a few weeks.

kdgregory