JAXB: How to ignore namespace during unmarshalling XML document? JAXB: How to ignore namespace during unmarshalling XML document? xml xml

JAXB: How to ignore namespace during unmarshalling XML document?

Here is an extension/edit of VonCs solution just in case someone doesn´t want to go through the hassle of implementing their own filter to do this. It also shows how to output a JAXB element without the namespace present. This is all accomplished using a SAX Filter.

Filter implementation:

import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.XMLFilterImpl;public class NamespaceFilter extends XMLFilterImpl {    private String usedNamespaceUri;    private boolean addNamespace;    //State variable    private boolean addedNamespace = false;    public NamespaceFilter(String namespaceUri,            boolean addNamespace) {        super();        if (addNamespace)            this.usedNamespaceUri = namespaceUri;        else             this.usedNamespaceUri = "";        this.addNamespace = addNamespace;    }    @Override    public void startDocument() throws SAXException {        super.startDocument();        if (addNamespace) {            startControlledPrefixMapping();        }    }    @Override    public void startElement(String arg0, String arg1, String arg2,            Attributes arg3) throws SAXException {        super.startElement(this.usedNamespaceUri, arg1, arg2, arg3);    }    @Override    public void endElement(String arg0, String arg1, String arg2)            throws SAXException {        super.endElement(this.usedNamespaceUri, arg1, arg2);    }    @Override    public void startPrefixMapping(String prefix, String url)            throws SAXException {        if (addNamespace) {            this.startControlledPrefixMapping();        } else {            //Remove the namespace, i.e. don´t call startPrefixMapping for parent!        }    }    private void startControlledPrefixMapping() throws SAXException {        if (this.addNamespace && !this.addedNamespace) {            //We should add namespace since it is set and has not yet been done.            super.startPrefixMapping("", this.usedNamespaceUri);            //Make sure we dont do it twice            this.addedNamespace = true;        }    }}

This filter is designed to both be able to add the namespace if it is not present:

new NamespaceFilter("http://www.example.com/namespaceurl", true);

and to remove any present namespace:

new NamespaceFilter(null, false);

The filter can be used during parsing as follows:

//Prepare JAXB objectsJAXBContext jc = JAXBContext.newInstance("jaxb.package");Unmarshaller u = jc.createUnmarshaller();//Create an XMLReader to use with our filterXMLReader reader = XMLReaderFactory.createXMLReader();//Create the filter (to add namespace) and set the xmlReader as its parent.NamespaceFilter inFilter = new NamespaceFilter("http://www.example.com/namespaceurl", true);inFilter.setParent(reader);//Prepare the input, in this case a java.io.File (output)InputSource is = new InputSource(new FileInputStream(output));//Create a SAXSource specifying the filterSAXSource source = new SAXSource(inFilter, is);//Do unmarshallingObject myJaxbObject = u.unmarshal(source);

To use this filter to output XML from a JAXB object, have a look at the code below.

//Prepare JAXB objectsJAXBContext jc = JAXBContext.newInstance("jaxb.package");Marshaller m = jc.createMarshaller();//Define an output fileFile output = new File("test.xml");//Create a filter that will remove the xmlns attribute      NamespaceFilter outFilter = new NamespaceFilter(null, false);//Do some formatting, this is obviously optional and may effect performanceOutputFormat format = new OutputFormat();format.setIndent(true);format.setNewlines(true);//Create a new org.dom4j.io.XMLWriter that will serve as the //ContentHandler for our filter.XMLWriter writer = new XMLWriter(new FileOutputStream(output), format);//Attach the writer to the filter       outFilter.setContentHandler(writer);//Tell JAXB to marshall to the filter which in turn will call the writerm.marshal(myJaxbObject, outFilter);

This will hopefully help someone since I spent a day doing this and almost gave up twice ;)

I have encoding problems with XMLFilter solution, so I made XMLStreamReader to ignore namespaces:

class XMLReaderWithoutNamespace extends StreamReaderDelegate {    public XMLReaderWithoutNamespace(XMLStreamReader reader) {      super(reader);    }    @Override    public String getAttributeNamespace(int arg0) {      return "";    }    @Override    public String getNamespaceURI() {      return "";    }}InputStream is = new FileInputStream(name);XMLStreamReader xsr = XMLInputFactory.newFactory().createXMLStreamReader(is);XMLReaderWithoutNamespace xr = new XMLReaderWithoutNamespace(xsr);Unmarshaller um = jc.createUnmarshaller();Object res = um.unmarshal(xr);

I believe you must add the namespace to your xml document, with, for example, the use of a SAX filter.

That means:

  • Define a ContentHandler interface with a new class which will intercept SAX events before JAXB can get them.
  • Define a XMLReader which will set the content handler

then link the two together:

public static Object unmarshallWithFilter(Unmarshaller unmarshaller,java.io.File source) throws FileNotFoundException, JAXBException {    FileReader fr = null;    try {        fr = new FileReader(source);        XMLReader reader = new NamespaceFilterXMLReader();        InputSource is = new InputSource(fr);        SAXSource ss = new SAXSource(reader, is);        return unmarshaller.unmarshal(ss);    } catch (SAXException e) {        //not technically a jaxb exception, but close enough        throw new JAXBException(e);    } catch (ParserConfigurationException e) {        //not technically a jaxb exception, but close enough        throw new JAXBException(e);    } finally {        FileUtil.close(fr); //replace with this some safe close method you have    }}