Output Namespace-Aware XML Documents
Check out this quick fix to create a namespace-aware DOM as a text file
by Kevin Jones
Using an XML DOM processor to create XML documents is relatively straightforward. Making these documents namespace aware is also easy; however, if you create a namespace-aware DOM, when you output the DOM as a text file the namespace data is lost. Try the code shown in Listing 1. The serializeNode() looks like this:
void serializeNode(
Node node, Writer out)
throws TransformerException
{
TransfomerFactory t =
TransformerFactory.
newInstance().
newTransformer();
DOMSource src =
new DOMSource(node);
StreamResult dest =
new StreamResult(out);
t.transform(src, dest);
}
What would you expect? I would expect to see:
<f:user xmlns:f="urn:users">
<name>kevin</name>
<age>41</age>
</f:user>
or something like it without the nice formatting. However, what you get instead is this (at least with the latest parser in JDK1.4.1 and with Xerces 2.4.0):
<f:user>
<name>kevin</name>
<age>41</age>
</f:user>
What is wrong with this picture? You've lost the namespace declaration. If you read this file back into a namespace-aware processor, you will get an exception (what I get from Xerces):
org.xml.sax.SAXParseException:
The prefix "f" for element
"f:user" is not bound.
at org.apache.xerces.
parsers.DOMParser.parse(
Unknown Source)
at org.apache.xerces.
jaxp.
DocumentBuilderImpl.
parse(Unknown Source)
at ejws.DOMRead.main
Fixing this problem is easy but smelly (from Refactoring: Improving the Design of Existing Code, by Martin Fowler [Addison-Wesley: 1999], where he talks about code that doesn't smell too good), you add an attribute that contains the namespace information to the DOM. Now we know that an attribute is not a namespace declaration, but this is what has to happen, so the code now looks like this, given this WSDL:
db = dbf.newDocumentBuilder();
Document doc =
db.newDocument();
// create a root element that
// 'looks' like this
// <f:user xmlns:f=
// "urn:users">
Node root =
doc.createElementNS(
"urn:users", "f:user");
doc.appendChild(root);
Attr attr =
doc.createAttribute(
"xmlns:f");
attr.setValue("urn:users");
((Element)root).
setAttributeNode(attr);
Now the output looks like this:
<f:user xmlns:f="urn:users">
<name>kevin</name>
<age>41</age>
</f:user>
A namespace-aware parser can now read this with no problems.
About the Author
Kevin Jones is a developer with more than 15 years of experience. He has spent the last four years researching and teaching Java programming and most recently investigating HTTP and XML. Kevin lives in the U.K. and works for Developmentor, a training company based in the United States and Europe that specializes in technical training on Java and Microsoft platforms. Reach Kevin at .
Back to top
|