I use Jaxb2 and Spring. I am trying to unmarshal some XML that are sent by 2 of my customers.
Up to now, I only had to handle one customer which sent some xml like this :
<foo xmlns="com.acme">
<bar>[...]</bar>
<foo>
that is bound to a POJO like this :
@XmlType(name = "", propOrder = {"bar"})
@XmlRootElement(name = "Foo")
public class Foo {
@XmlElement(name = "Bar")
private String bar;
[...]
}
I discovered that the previous developer hardcoded the namespace in the unmarshaller in order to make it work.
Now, the second customer sends the same XML but changes the namespace!
<foo xmlns="com.xyz">
<bar>[...]</bar>
<foo>
Obviously, the unmarshaller fails to unmarshall because it expects some {com.acme}foo
instead of {com.xyz}foo
. Unforunately, asking the customer to change the XML is not an option.
What I tried :
1) In application-context.xml
, I searched for a configuration which would allow me to ignore the namespace but could not find one :
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="packagesToScan">
<list>
<value>com.mycompany.mypkg</value>
</list>
</property>
<property name="marshallerProperties">
<map>
<entry key="???"><value type="java.lang.Boolean">false</value></entry>
</map>
</property>
</bean>
it seems that the only available options are the ones listed in the Jaxb2Marshaller's Javadoc :
/**
* Set the JAXB {@code Marshaller} properties. These properties will be set on the
* underlying JAXB {@code Marshaller}, and allow for features such as indentation.
* @param properties the properties
* @see javax.xml.bind.Marshaller#setProperty(String, Object)
* @see javax.xml.bind.Marshaller#JAXB_ENCODING
* @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT
* @see javax.xml.bind.Marshaller#JAXB_NO_NAMESPACE_SCHEMA_LOCATION
* @see javax.xml.bind.Marshaller#JAXB_SCHEMA_LOCATION
*/
public void setMarshallerProperties(Map<String, ?> properties) {
this.marshallerProperties = properties;
}
2) I also tried to configure the unmarshaller in the code :
try {
jc = JAXBContext.newInstance("com.mycompany.mypkg");
Unmarshaller u = jc.createUnmarshaller();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(false);//Tried this option.
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlFile.toFile());
u.unmarshal(new DOMSource(doc));
return (Foo)u.unmarshal(new StreamSource(xmlFile.toFile()));
} catch (ParserConfigurationException | SAXException | IOException | JAXBException e) {
LOGGER.error("Erreur Unmarshalling CPL");
}
3) Different form with a SAXParser :
try {
jc = JAXBContext.newInstance("com.mycompany.mypkg");
Unmarshaller um = jc.createUnmarshaller();
final SAXParserFactory sax = SAXParserFactory.newInstance();
sax.setNamespaceAware(false);
final XMLReader reader = sax.newSAXParser().getXMLReader();
final Source er = new SAXSource(reader, new InputSource(new FileReader(xmlFile.toFile())));
return (Foo)um.unmarshal(er);
}catch(...) {[...]}
This one works! But still, I would prefer to be able to autowire the Unmarshaller without needing this ugly conf everytime.
Thank you all, here shared my solution which works for my code , i try to make it generic every namespace contain ": " i write code if any tag have ":" it will remove from xml , This is used to skip namespace during unmarshalling using jaxb.
public class NamespaceFilter {
private NamespaceFilter() {
}
private static final String COLON = ":";
public static XMLReader nameSpaceFilter() throws SAXException {
XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {
private boolean skipNamespace;
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (qName.indexOf(COLON) > -1) {
skipNamespace = true;
} else {
skipNamespace = false;
super.startElement("", localName, qName, atts);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.indexOf(COLON) > -1) {
skipNamespace = true;
} else {
skipNamespace = false;
super.endElement("", localName, qName);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (!skipNamespace) {
super.characters(ch, start, length);
}
}
};
return xr;
}
}
for unmarshalling
XMLReader xr = NamespaceFilter.nameSpaceFilter();
Source src = new SAXSource(xr, new InputSource("C:\\Users\\binal\\Desktop\\response.xml"));
StringWriter sw = new StringWriter();
Result res = new StreamResult(sw);
TransformerFactory.newInstance().newTransformer().transform(src, res);
JAXBContext jc = JAXBContext.newInstance(Tab.class);
Unmarshaller u = jc.createUnmarshaller();
String done = sw.getBuffer().toString();
StringReader reader = new StringReader(done);
Tab tab = (Tab) u.unmarshal(reader);
System.out.println(tab);
`
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With