Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB: How to ignore namespace during unmarshalling XML document?

My schema specifies a namespace, but the documents don't. What's the simplest way to ignore namespace during JAXB unmarshalling (XML -> object)?

In other words, I have

<foo><bar></bar></foo> 

instead of,

<foo xmlns="http://tempuri.org/"><bar></bar></foo> 
like image 397
Eugene Yokota Avatar asked Nov 10 '08 10:11

Eugene Yokota


People also ask

How do I remove namespace prefix JAXB?

You can use the NamespacePrefixMapper extension to control the namespace prefixes for your use case. The same extension is supported by both the JAXB reference implementation and EclipseLink JAXB (MOXy).

What is namespace in XML document?

An XML namespace is a collection of names that can be used as element or attribute names in an XML document. The namespace qualifies element names uniquely on the Web in order to avoid conflicts between elements with the same name.

How do I set namespace prefix in JAXB?

If you are using the default JAXB implementation provided with Java 6 or later, you can configure the namespace prefixes by extending the NamespacePrefixMapper and setting a property to tell the marshaller to use your extension.

How do you Unmarshal XML string to Java object using JAXB?

To unmarshal an xml string into a JAXB object, you will need to create an Unmarshaller from the JAXBContext, then call the unmarshal() method with a source/reader and the expected root object.


1 Answers

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 objects JAXBContext jc = JAXBContext.newInstance("jaxb.package"); Unmarshaller u = jc.createUnmarshaller();  //Create an XMLReader to use with our filter XMLReader 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 filter SAXSource source = new SAXSource(inFilter, is);  //Do unmarshalling Object myJaxbObject = u.unmarshal(source); 

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

//Prepare JAXB objects JAXBContext jc = JAXBContext.newInstance("jaxb.package"); Marshaller m = jc.createMarshaller();  //Define an output file File 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 performance OutputFormat 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 writer m.marshal(myJaxbObject, outFilter); 

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

like image 130
Kristofer Avatar answered Sep 19 '22 22:09

Kristofer