I have a huge XML response from an external end point. I want to parse the XML response to java classes. I was able to parse into respective POJOS if none of the XML had namespaces and things went well till that point.
However, the response might contain namespaces only at the root element.
For eg, like this
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="somevalue here"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RestOfTheDocument> something here </RestOfTheDocument>
</Document>
I can guarantee that none of the inner xml elements will have any more namespaces.
Is there a way to implement this? I saw a few answers ignoring namespaces completely but dont feel very convincing. Is there a way to properly parse these.
This is my java class to model the XML response
#XmlRootElement(name = "Document")
static class Response {
#XmlElement(name = "RestOfTheDocument", required = true, nillable = false)
RestOfTheDocument restOfTheDocument;
}
what I tried ?
Add namespace information to the #XmlRootElement like this
#XmlRootElement(name = "Document", namespace = "somevalue here")
Doing so is making all the inner xml elements to be NULL.
NOTE: I have abstracted the huge inner level to be RestOfTheDocument but there are lot many but none of them will have any namespaces whatsoever in the response!
Thank you!
SimpleXml will ignore the namespaces and just parse the XML:
public class Document {
public String RestOfTheDocument;
}
final String data = ...;
final SimpleXml simple = new SimpleXml();
final Document document = simple.fromXml(data, Document.class);
System.out.println(document.RestOfTheDocument);
This will output:
something here
From maven central:
<dependency>
<groupId>com.github.codemonstur</groupId>
<artifactId>simplexml</artifactId>
<version>1.4.0</version>
</dependency>
Related
I would like to deserialize an XML subtree as string (with Jackson) in JAVA:
input structure:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<nodeA>text</nodeA>
<nodeB>
<nodeS>
<nodeS1>...</nodeS1>
<nodeS2>...</nodeS2>
</nodeS>
</nodeB>
</root>
into something like this:
public class Pojo {
#JacksonXmlProperty(localName="nodeA")
private String nodeA; // = "text"
#JacksonXmlProperty(localName="nodeB")
#JsonDeserialize(using = MyXmlDeserializer.class)
private String nodeB; // = "<nodeS><nodeS1>...</nodeS1><nodeS2>...</nodeS2></nodeS>"
}
The node nodeS should be taken as "raw-value" without ANY modifications to the xml and put it into a String class member.
I've tried it with custom deserializer or as #JacksonRawValue with no avail.
if one just could access the raw value of the "currentNode", that would help a lot.
Any alternative (jackson-related) solutions welcome :-)
It's kind of a workaround rather than a solution, but it's possible to use XmlMapper inside your JsonDeserializer:
xmlMapper.writeValueAsString(jsonNode);
As a result you'll get Xml string again. But as I wrote, it's workaround and I don't like it gets from Xml to Json, and from Json to Xml again.
If anyone get a better solution (using Jackson), please share.
I can't seem to work out how to set namespace when comparing XML's using xmlunit-2
Tried like:
#Test
public void testDiff_withIgnoreWhitespaces_shouldSucceed() {
// prepare testData
String controlXml = "<a><text:b>Test Value</text:b></a>";
String testXml = "<a>\n <text:b>\n Test Value\n </text:b>\n</a>";
Map<String, String> namespaces = new HashMap<String, String>();
namespaces.put("text","urn:oasis:names:tc:opendocument:xmlns:text:1.0");
// run test
Diff myDiff = DiffBuilder.compare(Input.fromString(controlXml).build())
.withTest(Input.fromString(testXml).build())
.withNamespaceContext(namespaces)
.ignoreWhitespace()
.build();
// validate result
Assert.assertFalse("XML similar " + myDiff.toString(), myDiff.hasDifferences());
}
but always get
org.xmlunit.XMLUnitException: The prefix "text" for element "text:b"
is not bound.
stripping away the namespace prefix from elements make it work, but I would like to learn how register properly the namespace with DiffBuilder.
The same problem/ignorence I experience with xmlunit-1.x so hints using that library I would appreciate as well.
EDIT, based on the answer
By adding the namespace attribute to the root node I managed to bind the namespace
<a xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">
thanks Stefan
NamespaceContext is only used for the XPath associated with the "targets" of comparisions. It is not intended to be used to provide mappings for the XML documents you compare.
There is no way of binding XML namespaces to prefixes outside of the documents themselves in XMLUnit. This means you either must use xmlns attributes or not use prefixes at all.
How can I accept different versions of namesspaces to unmarshal? I have many classes generated using JAXB. I want to unmarshal to get information from the XMLs. The problem is that the xmls have different xmlns versions.
I will make a simple example as the classes I have are too long.
Having the class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "attribute1"})
#XmlRootElement(name = "myClass", namespace = "http://www.test.com/xml-schema/MYC/1.0")
public class myClass {
#XmlElement(name = "attribute_1", namespace = "http://www.test.com/xml-schema/MYC/1.0", required = true)
protected String attribute1;
#XmlElement(name = "attribute_2", namespace = "http://www.test.com/xml-schema/MYC/1.0")
protected String attribute2;
}
I would like to accept not only a XML with the xmlns like:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Reha xmlns="http://www.test.com/xml-schema/MYC/1.0"
But as well xmlns like:
http://www.test.com/xml-schema/MYC/1.2
http://www.test.com/xml-schema/MYC/1.5
http://www.test.com/xml-schema/MYC/1.8
http://www.test.com/xml-schema/MYC/2.9
Having in mind I have other classes with other namesspaces, with the same problem (different versions in the namesspace)
I have read different posts but it is not clear for me. How could I achieve that?
After giving a deeper thought and understanding the user case.
In the case that a schema has different versions, it means that the structure of the XML changes, and that means that we will need two different classes to represent two different namespaces' versions, for example for the two different namespaces:
http://www.test.com/xml-schema/MYC/1.2
http://www.test.com/xml-schema/MYC/1.5
I have problem deserializing following xml:
<root>
<apples>
<apple>
<id>1</id>
<weight>0.6</id>
</apple>
<apple>
<id>2</id>
<weight>0.7</id>
</apple>
</apples>
</root>
to java:
public class Root {
private List<Fruits> fruits;
}
In above xml source other variants may be eg oranges/orange etc. also since this is propertary xml I cannot change it's schema. By default I am using #JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) and #JsonSubTypes({/*fruits subtypes listed*/}). After few unsuccessful attempts I am not sure what is the proper mapping/configuration to solve the problem.
Out of the box, Jackson is a JSON parser, not XML.
There are extensions for Jackson that allow for XML conversion. See http://wiki.fasterxml.com/JacksonExtensionXmlDataBinding for more info there. But it seems as though a pure XML parser may be better for this case.
Perhaps the javax.xml.stream.* packages.
i.e. http://www.javacodegeeks.com/2013/05/parsing-xml-using-dom-sax-and-stax-parser-in-java.html for more info.
I have an XML document that looks something like the following:
Note that I cannot change the schema because it is part of a standard XML Schema (Library of Congress METS).
<amdSec ID="AMDSEC001">
<digiprovMD ID="DMD001">
<mdWrap MDTYPE="OBJECT">
<xmlData>
<object xsi:type="file">
.....
</object>
</xmlData>
</mdWrap>
</digiprovMD>
<digiprovMD ID="DMD001_EVENT">
<mdWrap MDTYPE="EVENT">
<xmlData>
<event xsi:type="event">
.....
</event>
</xmlData>
</mdWrap>
</digiprovMD>
</amdSec>
As you can see, the inner element <mdWrap> can contain elements of different types; in this case they're <event> and <object>, but it isn't constrained to just those two types. Creating two classes (like below), marshals okay, but this doesn't work for unmarshalling.
class ObjectMDWrap {
#XmlElementWrapper(name = "xmlData")
#XmlElement(name = "object")
List<MyObject> object; //Wrapped in list to use #XmlElementWrapper
}
class EventMDWrap {
#XmlElementWrapper(name = "xmlData")
#XmlElement(name = "event")
List<MyEvent> event; //Wrapped in list to use #XmlElementWrapper
}
What can I do so that JAXB unmarshals the correct "type" of MDWrap?
I think, the best solution in this case is a generating POJO classes using XJC tool.
Download XSD file which describe XML file.
Using XJC tool convert XSD file into POJO classes. If XSD is not correct - fix it.
Make some changes if you need in generated classes.
Use this classes in marshalling / unmarshalling process.
I was able to figure out the solution, and it's much simpler than I initially thought (which speaks to my relative inexperience with XML and JAXB). By creating my MDWrap class in the following way
class MDWrap {
#XmlAnyElement(lax = true)
#XmlElementWrapper(name = "xmlData")
Object wrappedMD;
}
Then MDWrap can contain an object of any type, and will unmarshal properly, as long as the class of which wrappedMD is an instance of is annotated with #XmlRootElement. The trick is to annotate wrappedMD as XmlAnyElement.