Jabbering Giraffe

Writing XML in Java

Last night, I was looking at generating SAMS XML from Java objects. It made me realise two things:

  1. Java sucks badly at creating XML (by default).
  2. I should really be looking at XML Binding.

I’m interested in point 1. I’ve done it before, trying to write XML using DOM (as there doesn’t appear to be a builtin SAX writer). This is what I ended up with.

public abstract class AbstractXmlBuilder {
    protected void addXlinkHref(Element e, URI href) {
        e.setAttributeNS(Constants.XLINK_NS, "x:href", href.toString());
    }

    // See http://www.cafeconleche.org/books/xmljava/chapters/ch09s09.html
    // (JAXP Serialisation) for details on why all this palaver is necessary.
    protected String domToString(Document doc) {
        try {
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer trans = factory.newTransformer();
            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            DOMSource source = new DOMSource(doc);
            StringWriter writer = new StringWriter();
            StreamResult streamResult = new StreamResult(writer);
            trans.transform(source, streamResult);
            return writer.toString();
        } catch (TransformerConfigurationException e) {
            throw new RuntimeException(e);
        } catch (TransformerFactoryConfigurationError e) {
            throw new RuntimeException(e);
        } catch (TransformerException e) {
            throw new RuntimeException(e);
        }
    }

    protected Document newDocument(String namespaceURI, String qualifiedName) {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
            DOMImplementation impl = docBuilder.getDOMImplementation();
            return impl.createDocument(namespaceURI, qualifiedName, null);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    protected Document newDocument() {
        Document doc = newDocument(Constants.MY_NS, "doc");
        Element root = doc.getDocumentElement();
        root.setPrefix("my");
        // Set up the usual namespaces.
        root.setAttribute("xmlns:x", Constants.XLINK_NS);
        return doc;
    }

    protected Element myElem(Document doc, String name) {
        return doc.createElementNS(Constants.MY_NS, name);
    }
}

This is intended to be subclassed to be useful, but even in the subclasses, it still relies on dozens of helper methods. e.g.

    private Element getAccIdElem(SessionCreateRequest s, Document doc) {
        Element accId = myElem(doc, "acc_id");
        addXlinkHref(accId, s.getAccountId());
        return accId;
    }

This is incredibly verbose, but I don’t think we can do better with just the JDK. What are the other options? I’ve been looking at XOM. This appears to have a nice API for writing XML:

    Element root = new Element("root");
    root.appendChild("Hello World!");
    Document doc = new Document(root);
    System.out.println(doc.toXML());

This is much, much simpler. We’re still building a up a DOM-like structure, but it’s simpler to use.

But XOM is still a fairly large dependency. This doesn’t particularly matter for what I’m doing. But there are alternatives. Whilst looking for libraries, I also stumbled across xmlwriter. This is much lower-level:

  Writer writer = new java.io.StringWriter();
  XmlWriter xw = new SimpleXmlWriter(writer);
  xw.writeXmlVersion();
  xw.writeComment("Example of XmlWriter running");
  xw.writeEntity("person");
  xw.writeAttribute("name", "fred");
  xw.writeAttribute("age", "12");
  xw.writeEntity("phone");
  xw.writeText("4254343");
  xw.endEntity();
  xw.writeComment("Examples of empty tags");
  xw.writeEntity("friends");
  xw.writeEmptyEntity("bob");
  xw.writeEmptyEntity("jim");
  xw.endEntity();
  xw.writeEntityWithText("foo","This is an example.");
  xw.endEntity();
  xw.close();
  System.err.println(writer.toString());

This is closer to genx, a C library that I like very much. It’s quite weird that “element” and “entity” appear to be confused, though. Plus there doesn’t appear to be any way to generate canonical XML.

For now, I think I’ll stick with XOM, but it’s good to know that there are alternatives to the heavyweight JDK options.