My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
ExampleUsage  
How to use the XMLBuilder.
Featured
Updated Jun 12, 2011 by ja...@misterm.org

Create XML Document Parse XML Document Method Chaining Shorthand Methods Output/Serialization
Access the DOM Find Nodes with XPath

Example Usage

Read below for examples that show how you would use the XMLBuilder utility to create and manipulate XML documents like the following:

<?xml version="1.0" encoding="UTF-8"?>
<Projects>
    <java-xmlbuilder language="Java" scm="SVN">
        <Location type="URL">http://code.google.com/p/java-xmlbuilder/</Location>
    </java-xmlbuilder>
    <JetS3t language="Java" scm="CVS">
        <Location type="URL">http://jets3t.s3.amazonaws.com/index.html</Location>
    </JetS3t>
</Projects>

Create a New XML Document

To begin, you create a new builder and XML document by specifying the name of the document's root element. See ExampleUsage#Parse_XML if you want to start with an existing XML document.

XMLBuilder builder = XMLBuilder.create("Projects");

The XMLBuilder object returned by the create method, and by all other XML manipulation methods, provides methods that you can use to add more nodes to the document. For example, to add the java-xmlbuilder and JetS3t nodes to the root element you could do the following.

XMLBuilder e1 = builder.element("java-xmlbuilder");
XMLBuilder e2 = builder.element("JetS3t");

And to add attributes or further sub-elements to the two new elements, you could call the appropriate methods on the variables assigned to each new node like so:

e1.attribute("language", "Java");
e1.attribute("scm", "SVN");

This is straight-forward enough, but it is far more verbose than necessary because the code does not take advantage of XMLBuilder's method-chaining feature.

Method Chaining

Every XMLBuilder method that adds something to the XML document will return an XMLBuilder object that represents either a newly-added element, or the element to which something has been added. This feature means that you can chain together many method calls without the need to assign intermediate objects to variables.

With this in mind, here is code that performs the same job as the code above without any unnecessary variables.

XMLBuilder builder = XMLBuilder.create("Projects")
    .element("java-xmlbuilder")
        .attribute("language", "Java")
        .attribute("scm", "SVN")
        .element("Location")
        .up()
    .up()
    .element("JetS3t");

There are two important things to notice in the code above:

  • When you add a new element to the document with the element method, the XMLBuilder node returned will represent that new element. If you invoke methods on this node, attributes and elements will be added to the new node rather than to the document's root.
  • Once you have finished adding items to a new element, you can call the up() method to retrieve the XMLBuilder node that represents the parent of the current node. If you balance every call to element() with a call to up(), you can write code that closely resembles the structure of the XML document you are creating.

Shorthand Methods

To make your XML building code even shorter and easier to type, there are shorthand synonyms for every XML manipulation method. Instead of calling element() you can use the elem() or e() methods, and instead of typing attribute() you can use attr() or a().

Here is the complete code to build our example XML document using shorthand methods.

XMLBuilder builder = XMLBuilder.create("Projects")
    .e("java-xmlbuilder")
        .a("language", "Java")
        .a("scm","SVN")                    
        .e("Location")
            .a("type", "URL")
            .t("http://code.google.com/p/java-xmlbuilder/")
        .up()
    .up()
    .e("JetS3t")
        .a("language", "Java")
        .a("scm","CVS")
        .e("Location")
            .a("type", "URL")
            .t("http://jets3t.s3.amazonaws.com/index.html");

The following methods are available for adding items to the XML document:

XML Node Methods
Elementelement, elem, e
Attributeattribute, attr, a
Text (Element Value)text, t
CDATAcdata, data, d
Commentcomment, cmnt, c
Process Instructioninstruction, inst, i
Referencereference, ref, r

Output

XMLBuilder includes two convenient methods for outputting a document.

You can use the toWriter method to print the document to an output stream or file:

PrintWriter writer = new PrintWriter(new FileOutputStream("projects.xml"));
builder.toWriter(writer, outputProperties);

Or you can convert the document straight to a text string:

builder.asString(outputProperties);

Both of these output methods take an outputProperties parameter that you can use to control how the output is generated. Any output properties you provide are forwarded to the underlying Transformer object that is used to serialize the XML document. You might specify any non-standard properties like so:

Properties outputProperties = new Properties();

// Explicitly identify the output as an XML document
outputProperties.put(javax.xml.transform.OutputKeys.METHOD, "xml");

// Pretty-print the XML output (doesn't work in all cases)
outputProperties.put(javax.xml.transform.OutputKeys.INDENT, "yes");

// Get 2-space indenting when using the Apache transformer
outputProperties.put("{http://xml.apache.org/xslt}indent-amount", "2");

// Omit the XML declaration header
outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");

If you do not wish to change the default properties for your output, you can provide a null value for outputProperties.

Accessing the Underlying Document

Because XMLBuilder merely acts as a layer on top of the standard JAXP XML document building tools, you can easily access the underlying Element or Document objects if you need to manipulate them in ways that XMLBuilder does not allow.

To obtain the Element represented by any given XMLBuilder node:

org.w3c.dom.Element element = xmlBuilderNode.getElement();

To obtain the entire XML document:

org.w3c.dom.Document doc = builder.getDocument();

You can also use the root() method to quickly obtain the builder object that represents the document's root element, no matter deep an element hierarchy your code has built:

org.w3c.dom.Element rootElement = 
    XMLBuilder.create("This")
        .e("Element")
            .e("Hierarchy")
                .e("Is")
                    .e("Really")
                        .e("Very")
                            .e("Deep")
                                .e("Indeed")
    .root().getElement();

Parse XML

If you already have an XML document to which you need to add nodes or attributes, you can create a new XMLBuilder instance by parsing an InputSource:

XMLBuilder builder = XMLBuilder.parse(
   new InputSource(new StringReader(YOUR_XML_DOCUMENT)));

Parsing an existing document will produce an XMLBuilder object pointing at the document's root Element node. If you add elements or attributes to this builder object, they will be added to the document's root element.

If you need to add nodes elsewhere in the parsed document, you will need to find the correct location in the document using XPath statements.

Find Nodes with XPath

To add nodes at a specific point in an XML document, you can use XPath to obtain an XMLBuilder at the correct location. The XMLBuilder#xpathFind method takes an XPath query string and returns a builder object located at the first Element that matches the query.

XMLBuilder firstLocationBuilder = builder.xpathFind("//Location");

Note that the XPath query provided to this method must resolve to at least one Element node. If the query does not match any nodes, or if the first match is anything other than an Element, the method will throw an XPathExpressionException.

Like all other XMLBuilder methods, this method can be easily chained to others when adding nodes. Here is an example that adds a second element, Location2, inside the JetS3t element of our example document.

builder.xpathFind("//JetS3t").elem("Location2").attr("type", "Testing");

To produce:

<Projects>
  <java-xmlbuilder language="Java" scm="SVN">
    <Location type="URL">http://code.google.com/p/java-xmlbuilder/</Location>
  </java-xmlbuilder>
  <JetS3t language="Java" scm="CVS">
    <Location type="URL">http://jets3t.s3.amazonaws.com/index.html</Location>
    <Location2 type="Testing"/>
  </JetS3t>
</Projects>
Comment by e.alblou...@gmail.com, Jun 12, 2009

Nice & Simple thank you for your great effort

Emad Al-Bloushi

Comment by king...@gmail.com, Jul 5, 2009

VEry nice and useful (feels like jquery).

But do you have some performance comparisons with existing xml parsers/builders? (dom4j,...).

Keep up the great work!

Comment by xfg...@gmail.com, Oct 13, 2009

I like the idea very much. But wouldn't it be better if it doesn't create a new builder on every call. How about return simply this on every call and at the same time mark the current element/position inside the Builder. For instance,

...

public XmlRequestBuilder? root() {

xmlElement = xmlDocument.getDocumentElement(); return this;
}

public XMLBuilder element(String name) {

... Element newElement = xmlDocument.createElement(name); xmlElement.appendChild(newElement); xmlElement = newElement; return this;
}

Comment by project member jamu...@gmail.com, May 8, 2010

@kinglew: Using XMLBuilder is likely to produce some overhead compared to other XML parsers/builders. The aim of the library is to make it simple to build small XML documents -- in its current state it mightn't be a good match if you need to produce large docs very quickly.

@xfglin: Restructuring XMLBuilder to remember the current DOM location instead of always constructing new builder objects would have plusses and minuses. On the plus side it would make the library faster and reduce demand for memory, but on the minus side it would complicate the class a little and make it harder to use in some situations, such as if you wanted to have multiple builder objects at once that manipulate different parts of the DOM.

If there is demand I might look into making the changes you suggest.

Comment by amer...@gmail.com, Jun 20, 2010

After small research on web, i was going to start my projet on google code, but before, just to clear my mind, i've done a little searched on google code and found your tools. the same as mine but much better, thanks a lot. this will shorten my unit tests and i will make them faster.

Comment by houre...@hotmail.com, Sep 8, 2010

After importing the jar file into the project, what does the import statement for the class look like?

import .....XMLBuilder;

Comment by vivekris...@gmail.com, Jan 12, 2011

THis is really helpful for me. Just a quick question.

How do I encode the xml document? like, how do I set this line,

<?xml version="1.0" encoding="UTF-8">

My primary purpose is to change the encoding.

Comment by project member ja...@misterm.org, Jan 12, 2011

@houreich: The import statement is "import com.jamesmurty.utils.XMLBuilder". Sorry for the late reply, Google Code doesn't notify me when new comments arrive.

@vivekrishna: You can control the encoding by setting the ENCODING output property. There are instructions for using output properties in the "Output" section above and something like the following output setting should do what you need:

outputProperties.put(javax.xml.transform.OutputKeys?.ENCODING, "UTF-16");

Comment by cw10...@gmail.com, Mar 22, 2011

This is a great utility wrapper, but xpath finder doesn't seem to work with namespaces, or it's not clearly documented.

Comment by project member ja...@misterm.org, Mar 23, 2011

XMLBuilder does support namespaces but only in the latest code, which was added after the 0.4 release.

To use namespaces, check out the current code and see the testNamespaces test method for examples: http://code.google.com/p/java-xmlbuilder/source/browse/trunk/src/test/java/com/jamesmurty/utils/TestXmlBuilder.java#273

Comment by cw10...@gmail.com, Mar 24, 2011

Mirabile dictu! It worked! Thanks...

Comment by rsoesem...@logicline.de, Apr 7, 2011

Thank your for this timesaver. I use your lib in nearly every project. But now I have a problem when doing xPathFind on a 17 Meg XML.

When calling:


XMLBuilder cdataBuilder = builder.xpathFind("//" + rootNodeName + "/" + nodeName);

I get an:


java.lang.OutOfMemoryError? at java.lang.String.<init>(String.java:298) at java.lang.StringBuffer?.toString(StringBuffer?.java:790) at org.apache.xerces.dom.DeferredDocumentImpl?.getNodeValueString(Unknown Source) at org.apache.xerces.dom.DeferredDocumentImpl?.getNodeValueString(Unknown Source) at org.apache.xerces.dom.DeferredCDATASectionImpl.synchronizeData(Unknown Source) at org.apache.xerces.dom.CharacterDataImpl?.getNodeValue(Unknown Source) at org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.nextNode(Unknown Source) at org.apache.xml.dtm.ref.DTMDefaultBase.nextsib(Unknown Source) at org.apache.xml.dtm.ref.DTMDefaultBase.getNextSibling(Unknown Source) at org.apache.xml.dtm.ref.DTMDefaultBaseTraversers$ChildTraverser?.next(Unknown Source) at org.apache.xpath.axes.AxesWalker?.getNextNode(Unknown Source) at org.apache.xpath.axes.AxesWalker?.nextNode(Unknown Source) at org.apache.xpath.axes.WalkingIterator?.nextNode(Unknown Source) at org.apache.xpath.axes.NodeSequence?.nextNode(Unknown Source) at org.apache.xpath.axes.NodeSequence?.runTo(Unknown Source) at org.apache.xpath.axes.NodeSequence?.setRoot(Unknown Source) at org.apache.xpath.axes.LocPathIterator?.execute(Unknown Source) at org.apache.xpath.XPath.execute(Unknown Source) at org.apache.xpath.jaxp.XPathExpressionImpl.evaluate(Unknown Source) at com.jamesmurty.utils.XMLBuilder.xpathQuery(XMLBuilder.java:307) at com.jamesmurty.utils.XMLBuilder.xpathFind(XMLBuilder.java:363) at com.jamesmurty.utils.XMLBuilder.xpathFind(XMLBuilder.java:389)

Comment by project member ja...@misterm.org, Apr 7, 2011

@rsoesem: To process large XML documents you will need to increase the memory that's available to your JVM, such as by using the -Xmx flag. DOM-based XML processing, as used by XMLBuilder, tends to use a lot of memory for large documents.

Comment by rsoesem...@logicline.de, Apr 11, 2011

I changed my code and my JVM memory settings and now it worked!

Comment by raghav.a...@gmail.com, Jun 12, 2011

when i call asSTring on the builder it appends "<?xml version="1.0" encoding="UTF-8" standalone="no"?>" at the start, is thr a way to disable it?

Comment by project member ja...@misterm.org, Jun 12, 2011

@raghav: See the updated Output/Serialization section above

Comment by raghav.a...@gmail.com, Jun 14, 2011

thx james...i m working on an xmpp server and hv to generate lot of simple xml stanzas. i was just exploring ur lib and found it gr8. I have a slight issue: XmlBuilder? methods throw a lot of checked exceptions, i was just wondering if they could be runtime as the client code of the lib ends up with a lot of exception handling code. I can also manage with creating a wrapper on top of builder.

Comment by psychobr...@gmail.com, Jun 28, 2011

How do you add DOCTYPEs to the top of an XML document?

Your create method opens the first element all nice and dandily - before you can set a DOCTYPE.

Comment by project member ja...@misterm.org, Jun 28, 2011

@psychobr: Use output properties like the following when generating XML output:

outputProperties.put(javax.xml.transform.OutputKeys?.DOCTYPE_PUBLIC, "MyType?"); outputProperties.put(javax.xml.transform.OutputKeys?.DOCTYPE_SYSTEM, "MySystem?");


Sign in to add a comment
Powered by Google Project Hosting