Unmarshalling

This page contains questions on unmarshalling JaxMe objects from XML documents.

Namespace conversion

I have documents in the wrong/with/without namespace. How can I unmarshal them?

This problem arises typically when unmarshalling documents from an external source, which aren't under your control. For example, a legacy application creates so-called XML but chooses to ignore the namespace declaration. The solution is to transform the incoming XML into a valid document by converting the elements namespace.

In what follows, I take the following assumptions, for the sake of simplicity:

1.) All elements of the incoming document have no namespace. They should be converted to namespace http://foo.com/xml.

2.) All attributes of the incoming document have no namespace, which is fine. Attributes are being left unchanged.

To understand what's happening, I'll begin with a quick and dirty solution. We convert the incoming document into DOM, transform the DOM document, and unmarshal that.

    java.io.File f = "myfile.xml";
    javax.xml.parsers.DocumentBuilder db = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();
    db.setValidating(false);
    db.setNamespaceAware(true);
    org.w3c.dom.Document doc = db.parse(f.toURL().toString());
    convert(doc);
    javax.xml.bind.JAXBContext context = javax.xml.bind.JAXBContext.newInstance("com.foo.xml");
    javax.xml.bind.Element e = (javax.xml.bind.Element) context.createUnmarshaller().unmarshal(doc);

The example uses a method convert(org.w3c.dom.Node), which could be written like this:

    private void convert(org.w3c.dom.Node pNode) {
        if (pNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
            String uri = pNode.getNamespaceURI();
            if (uri == null  ||  "".equals(uri)) {
                pNode.setNamespaceURI("http://foo.com/xml");
            }
        }
        for (org.w3c.dom.Node child = pNode.getFirstChild();  child != null;  child = child.getNextSibling()) {
            convert(child);
        }
    }

So far for DOM. But you should not use DOM, because it is slow and very memory consuming. The better (but a little bit more complicated) approach is using a SAX handler. The SAX handler needs almost no memory and can be immediately attached to the unmarshaller. To illustrate the SAX example, we'll begin with the SAX handler. It extends org.xml.sax.helpers.XMLFilterImpl:

    public class Converter extends org.xml.sax.helpers.XMLFilterImpl {
        private String convert(String pNamespaceURI) throws SAXException {
            if (pNamespaceURI == null  ||  "".equals(pNamespaceURI)) {
                return "http://foo.com/xml";
            } else {
                return pNamespaceURI;
            }
        }
        public void startElement(String pNamespaceURI, String pLocalName, String pQName,
                                 Attributes pAttrs) throws SAXException {
            super.startElement(convert(pNamespaceURI), pLocalName, pQName, pAttrs);
        }
        public void endElement(String pNamespaceURI, String pLocalName, String pQName) throws SAXException {
            super.startElement(convert(pNamespaceURI), pLocalName, pQName);
        }
        public void startPrefixMapping(String pPrefix, String pNamespaceURI) throws SAXException {
            super.startPrefixMapping(pPrefix, convert(pNamespaceURI));
        }
    }

The handler should be straightforward. Here's how to use it:

    java.io.File f = "myfile.xml";
    javax.xml.parsers.SAXParser sp = javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser();
    sp.setValidating(false);
    sp.setNamespaceAware(true);
    Converter converter = new Converter();
    converter.setParent(sp.getXMLReader());
    javax.xml.bind.JAXBContext context = javax.xml.bind.JAXBContext.newInstance("com.foo.xml");
    javax.xml.bind.UnmarshallerHandler uh = context.createUnmarshaller().getUnmarshallerHandler();
    converter.setContentHandler(uh);
    converter.parse(new org.xml.sax.InputSource(f.toURL().toString()));
    javax.xml.bind.Element e = (javax.xml.bind.Element) uh.getResult();

JaxMe/FrequentlyAskedQuestions/Unmarshalling (last edited 2009-09-20 22:48:10 by localhost)