Missed writing out an XML element end tag in your Java codes? You’re not alone. It is acceptable for small XML documents because spotting the erring codes is relatively easy. However, things may get very frustrating when writing huge XML documents with numerous elements that may be recursive or hierarchical in structure, even if you validate it against some XSDs. This post shows how to write XML tags in a more convenient way using lambdas in Java.
Using XMLStreamWriter To Write Out XML Tags
Now consider the following Java codes that directly use the XMLStreamWriter class to write out XML tags. Moreover, the codes write out a simple XML document to a file. Using this approach works for small XMLs. However, it may not be practical for dealing with huge and complex XMLs because we have to
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class XmlWriterDemo { public static void main(String[] args) throws UnsupportedEncodingException, XMLStreamException, FileNotFoundException { OutputStream outputStream = new FileOutputStream(new File("doc.xml")); XMLStreamWriter out = XMLOutputFactory.newInstance().createXMLStreamWriter( new OutputStreamWriter(outputStream, "utf-8")); out.writeStartDocument(); out.writeStartElement("doc"); out.writeStartElement("title"); out.writeCharacters("Document Title"); out.writeEndElement(); out.writeEndElement(); out.writeEndDocument(); out.close(); } } |
Note how the we position the writeStartElement and writeEndElement calls. We write them accordingly so that open and close tags match up. What if you missed out on the code in either line 15 or 16? Perhaps accidentally swapped them with each other?
Using Java Lambda
We need some wrapper class from which to use the @FunctionalInterface.
First, this is our functional interface:
1 2 3 4 5 | @FunctionalInterface public interface RecursiveElementWriterFunctionalInterface { void write() throws Exception; } |
The wrapper class looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import javax.xml.stream.XMLStreamWriter; public class XmlStreamWriterWrapper { private XMLStreamWriter xmlStreamWriter; public XmlStreamWriterWrapper(XMLStreamWriter xmlStreamWriter) { this.xmlStreamWriter = xmlStreamWriter; } public void writeElementBlock(String elementName, RecursiveElementWriterFunctionalInterface functionalInterface) throws Exception { this.xmlStreamWriter.writeStartElement(elementName); functionalInterface.write(); this.xmlStreamWriter.writeEndElement(); } } |
For simplicity, an XMLStreamWriter object is passed to the constructor.
Write Out XML Tags Using The Functional Interface And Lambda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class XmlWriterDemo { public static void main(String[] args) throws Exception { OutputStream outputStream = new FileOutputStream(new File("doc.xml")); XMLStreamWriter out = XMLOutputFactory.newInstance().createXMLStreamWriter( new OutputStreamWriter(outputStream, "utf-8")); XmlStreamWriterWrapper wrapper = new XmlStreamWriterWrapper(out); out.writeStartDocument(); wrapper.writeElementBlock("doc", () -> { wrapper.writeElementBlock("title", () -> { out.writeCharacters("Document Title"); }); }); out.writeEndDocument(); out.close(); } } |
The codes above are made as simple as possible to demonstrate the idea of writing out XML tags using Java lambdas. It is even possible to create a method writeStartDocumentBlock(String, RecursiveElementWriterFunctionalInterface) for writeStartDocument and writeEndDocument methods.
So, how about using JAXB? Not an option! It is too slow. Most people who have dealt with XMLs avoid it. It is worth nothing that we are just adding a level of abstract on top of Java classes that we typically use for XML processing. This technique may not significantly improve application performance but it will not be as bad as using JAXB.
This post is part of a reboot Java tutorial.