Creating and Modifying XML in Java
Almost two years ago, I wrote a blog with code (found here) that parsed XML easily using the Apache Xerces DOM parser. In the blog, I wrote some helper methods to locate XML elements and return their values in a less verbose way. This proved to be one of my most popular blog entries to date. However, one reader commented that it would be nice to add helper methods to easily create or modify XML, not just parse it. This blog is the answer to that request.
I've added two new helper methods to the code I presented last time:
setNodeValue
— takes an element (or tag) name, aString
value, and the list of nodes within which the existing node can be foundaddNode
— takes an element (or tag) name, aString
value, and the parent node for which the new node is to be a child of
Let's look at setNodeValue
, which is meant to set the value of an existing XML element within your XML document:
protected void setNodeValue(String tagName, String value, NodeList nodes) { Node node = getNode(tagName, nodes); if ( node == null ) return; // Locate the child text node and change its value NodeList childNodes = node.getChildNodes(); for (int y = 0; y < childNodes.getLength(); y++ ) { Node data = childNodes.item(y); if ( data.getNodeType() == Node.TEXT_NODE ) { data.setNodeValue(value); return; } } }
The code works by first locating the specified node within the list of nodes provided. If it's not found, the method returns without doing anything. Otherwise it locates the node's text value child node, sets that child node's value to the new value, and returns. Pretty straightforward but somewhat verbose, and definitely not something you want to repeat all over your code. As a result, this helper method comes in handy.
Next, let's look at addNode
, which adds a new XML element, with value, to your XML document:
protected void addNode(String tagName, String value, Node parent) { Document dom = parent.getOwnerDocument(); // Create a new Node with the given tag name Node node = dom.createElement(tagName); // Add the node value as a child text node Text nodeVal = dom.createTextNode(value); Node c = node.appendChild(nodeVal); // Add the new node structure to the parent node parent.appendChild(node); }
To create any type of Node
or Element
object with the Xerces parser, you need a reference to the XML document's Document
object. Any existing Node
or Element
can provide this via a call to getOwnerDocument
. Next, we create a generic Element
object with the element tag name provided. Then, we create a specific Text Node
with the value provided, and append it to the new Element
created prior. Finally, the Element
(with its child Text Node
) is added as a child to the parent Node
provided, and our work is done.
Using the Methods
In my previous blog, I presented code that simply parsed the XML and read the values of some tags, as such:
DOMParser parser = new DOMParser(); parser.parse("mydocument.xml"); Document doc = parser.getDocument(); // Get the document's root XML node NodeList root = doc.getChildNodes(); // Navigate down the hierarchy to get to the CEO node Node comp = getNode("Company", root); Node exec = getNode("Executive", comp.getChildNodes() ); String execType = getNodeAttr("type", exec); // Load the executive's data from the XML NodeList nodes = exec.getChildNodes(); String lastName = getNodeValue("LastName", nodes ); String firstName = getNodeValue("FirstName", nodes); String street = getNodeValue("street", nodes ); ...
I won't go into detail here as this is all explained in the previous blog. Instead, let's modify the value of the "street"
tag, assuming the company moved:
setNodeValue("street", "456 Maple Avenue", nodes);
Next, let's add the person's phone number, which was missing in the original XML:
addNode("Phone", "123-456-7890", exec );
And that's it. Very simple and one line of code for changes made to the XML.
Serializing the DOM
After using these two methods to modify your XML document, you may want to write the content out as an XML file to disk. To do so, you need to serialize the Document
as shown in this abbreviated sample code that loads an XML document, modifies it, and then saves it back to disk:
// First read the XML file and parse DOMParser parser = new DOMParser(); parser.parse("mydocument.xml"); Document doc = parser.getDocument(); // Modify the XML ... // Write updated XML doc = parser.getDocument(); OutputFormat format = new OutputFormat(doc); format.setIndenting(true); String filename = "mydocument"+System.currentTimeMillis()+".xml"; XMLSerializer serializer = new XMLSerializer( new FileOutputStream(new File(filename)), format); serializer.serialize(doc);
When beginning the serialization process, it's important to call getDocument
again to be sure we have the updated Document
structure. Next, set the formatting to maintain indentation. To preserve the original XML file, a new filename is created. Finally, the Xerces XMLSerializer
is used to write the contents of the Document
to a new file with the given filename. Of course, you can alternatively provide the previous file to overwrite it.
The Xerces parser makes it easy to create and parse XML documents, although some of the API leads to verbose Java code. This blog, combined with the previous one I wrote, makes it much easier to perform common operations when parsing and modifying your XML files. I hope you find it useful.
Happy Coding!
-EJB