Unmarshalling XML without a namespace using JAXB
Ok, this is just a short post on unmarshalling XML which doesn’t have a namespace but the objects that you have do have a namespace.
Right, first you’ll need two XSDs which have some objects that you’ll be receiving in String XML format:
vsf-payload.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.v-s-f.co.uk/payload"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.v-s-f.co.uk/payload"
xmlns:vsfd="http://www.v-s-f.co.uk/domain">
<import namespace="http://www.v-s-f.co.uk/domain" schemaLocation="vsf-domain.xsd" />
<element name="VsfPayload" type="tns:VsfPayload" />
<complexType name="VsfPayload">
<sequence>
<element name="VsfDomain" type="vsfd:VsfDomain" />
</sequence>
</complexType>
</schema>
vsf-domain.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.v-s-f.co.uk/domain"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.v-s-f.co.uk/domain">
<element name="VsfDomain" type="tns:VsfDomain" />
<complexType name="VsfDomain">
<sequence>
<element name="Hello" type="string" />
</sequence>
</complexType>
</schema>
In order to get the above XSDs generated into objects we can use the XJC plugin for maven:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-xjc-plugin</artifactId>
<version>2.3.0</version>
<configuration>
<extensions>
<extension>org.apache.cxf.xjcplugins:cxf-xjc-dv:2.3.0</extension>
</extensions>
</configuration>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>xsdtojava</goal>
</goals>
<configuration>
<sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
<xsdOptions>
<xsdOption>
<xsd>${basedir}/src/main/resources/vsf-payload.xsd</xsd>
</xsdOption>
</xsdOptions>
</configuration>
</execution>
</executions>
</plugin>
Run a clean install to generate the objects.
Open the created class VsfPayload and add a root element tag to the top:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "VsfPayload", propOrder = {
"vsfDomain"
})
@XmlRootElement
public class VsfPayload {
Create a test class for testing the unmarshalling as follows:
package uk.co.vsf.utilities;
import java.io.StringReader;
import static org.testng.Assert.*;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import uk.co.v_s_f.domain.VsfDomain;
import uk.co.v_s_f.payload.VsfPayload;
public class XMLTrial {
@Test
public void testMarshall() throws JAXBException
{
marshallHelloWorld();
}
private String marshallHelloWorld() throws JAXBException
{
VsfPayload payload = new VsfPayload();
VsfDomain domain = new VsfDomain();
domain.setHello("Hello World");
payload.setVsfDomain(domain);
return writeXMLOut(payload);
}
private String writeXMLOut(VsfPayload payload) throws JAXBException
{
JAXBContext jc = JAXBContext.newInstance(VsfPayload.class.getPackage().getName());
//Create unmarshaller
Marshaller marshaller = jc.createMarshaller();
//Unmarshal XML contents of the file myDoc.xml into your Java
StringWriter sw = new StringWriter();
marshaller.marshal(payload, sw);
return sw.getBuffer().toString();
}
}
The method, testMarshall, writes out the XML string produced when marshalling the object and shows you what you should be expecting if you’d received a well formed XML message complete with namespaces.
Now we add a new method to the test class which will unmarshall a string that has no namespace information (so the complete file is now…):
package uk.co.vsf.utilities;
import java.io.StringReader;
import static org.testng.Assert.*;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import com.testexample.payload.ContentWrapper;
import uk.co.v_s_f.domain.VsfDomain;
import uk.co.v_s_f.payload.VsfPayload;
public class XMLTrial {
@Test
public void testMarshall() throws JAXBException
{
marshallHelloWorld();
}
private String marshallHelloWorld() throws JAXBException
{
VsfPayload payload = new VsfPayload();
VsfDomain domain = new VsfDomain();
domain.setHello("Hello World");
payload.setVsfDomain(domain);
return writeXMLOut(payload);
}
@Test
public void domToObjects() throws Exception
{
String xml = "<ContentWrapper><VsfPayload><VsfDomain><Hello>Hello World</Hello></VsfDomain></VsfPayload></ContentWrapper>";
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
Document doc = db.parse(is);
JAXBContext jc = JAXBContext.newInstance(ContentWrapper.class.getPackage().getName());
//Create unmarshaller
Unmarshaller unmarshaller = jc.createUnmarshaller();
//Unmarshal XML contents of the file myDoc.xml into your Java
StringWriter sw = new StringWriter();
ContentWrapper wrapper = (ContentWrapper) unmarshaller.unmarshal(doc.getFirstChild());
assertEquals(writeXMLOut(wrapper.getVsfPayload()), marshallHelloWorld());
}
private String writeXMLOut(VsfPayload payload) throws JAXBException
{
JAXBContext jc = JAXBContext.newInstance(VsfPayload.class.getPackage().getName());
//Create unmarshaller
Marshaller marshaller = jc.createMarshaller();
//Unmarshal XML contents of the file myDoc.xml into your Java
StringWriter sw = new StringWriter();
marshaller.marshal(payload, sw);
return sw.getBuffer().toString();
}
}
But there’s an object in that new method which won’t compile without it being created. ContentWrapper is another xjc created class so add another XSD file:
wrapper.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.testexample.com/payload"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.testexample.com/payload"
xmlns:vsfp="http://www.v-s-f.co.uk/payload">
<import namespace="http://www.v-s-f.co.uk/payload" schemaLocation="vsf-payload.xsd" />
<element name="ContentWrapper" type="tns:ContentWrapper" />
<complexType name="ContentWrapper">
<sequence>
<element name="VsfPayload" type="vsfp:VsfPayload" />
</sequence>
</complexType>
</schema>
That new XSD contains a single element ContentWrapper which contains the VsfPayload object. Change your pom to reference the wrapper file, not the payload file:
...
<xsd>${basedir}/src/main/resources/wrapper.xsd</xsd>
...
And regenerate the objects by running a clean install. Re-edit the VsfPayload object to add the root element tag. Also edit the ContentWrapper class to add the following xml root elemetn tag:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ContentWrapper", propOrder = {
"vsfPayload"
})
@XmlRootElement(name="ContentWrapper", namespace="")
public class ContentWrapper {
Now your test class should compile. The second test method in the test class, domToObjects, will pass an XML string into a Document and then get the first node, ContentWrapper and then unmarshall that node. Following that, it will marshall the objects to confirm that the string representation looks exactly like the first method, testMarshall.
Anyway, that’s one solution for unmarshalling xml that doesn’t have a namespace. There’s probably a way to add a binding override to force ContentWrapper to be created with a blank namespace and a root element tag too.

Please enable the Disqus feature in order to add comments