Reputation:
I am writing an XML parser in Java for a simple xml structure that has a structure that starts with
<Document xmlns="some value" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
Im able to read the entire XML structure just fine except this line. Im able to parse and read into respective JAVA POJOs using JAXB without the xmlns attribute. However, If I add that the parser throws an exception.
What I tried,
@XmlRootElement(name = "Document")
static class UserMetaData {
@XmlAttribute(name = "xmlns:xsi", required = true)
String xmlnsXsi;
@XmlAttribute(name = "xmlns", required = true)
String xmlns;
@XmlElement(name = "User", required = true, nillable = false)
User userRecord;
}
Upvotes: 3
Views: 1405
Reputation: 2419
Edit
Successfully working with the following code:
@Test
public void unmarshal() throws JAXBException {
JAXBContext context = JAXBContext.newInstance(UserData.class);
Unmarshaller unmarshaler = context.createUnmarshaller();
StringReader reader = new StringReader("<Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:pain.002.001.03\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><User/></Document>");
UserData result = (UserData) unmarshaler.unmarshal(reader);
System.out.println(result.userRecord);
}
And the bean:
@XmlRootElement(name = "Document", namespace="urn:iso:std:iso:20022:tech:xsd:pain.002.001.03")
public class UserData {
@XmlElement(name = "User", required = true, nillable = false)
public User userRecord;
}
Assuming you have:
<Document xmlns="http://test.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
Remove these:
@XmlAttribute(name = "xmlns:xsi", required = true)
String xmlnsXsi;
@XmlAttribute(name = "xmlns", required = true)
String xmlns;
You don't need to map namespaces as attributes.
Your need to define root element with the namespace:
@XmlRootElement(name = "Document", namespace= "http://test.com")
To explain it a bit further. Imagine that in XML you have 2 different types of users. One user is DB user with name, login, and password, another user has name, and certificate.
You may create something like:
<user name="">
<login></login>
<password></password>
<cert></cert>
</user>
But such structure doesn't fit the requirement. User definitions are different. So, you probably want to create 2 definitions:
<user name="">
<login></login>
<password></password>
</user>
<user name="">
<cert></cert>
</user>
But how to distinguish these 2 definitions in the same XML? This is the purpose of namespaces. They allow to use tags with the same names but different content in the same XML document:
<Document>
<user name="" xmlns="http://user1.com">
<login></login>
<password></password>
</user>
<user name="" xmlns="http://user2.com">
<cert></cert>
</user>
</Document>
The first user tag is defined in the http://user1.com namespace, the second user tag is defined in the http://user2.com namespace. They are not clashing anymore and are treated as 2 different names with different definitions.
However, mentioning xmlns="http://user1.com" or xmlns="http://user2.com" for every tag is tedious. Namespace aliases are a great help here. You can define any namespace alias in the root element and use alias as tag prefix. For our example, we will define 2 aliases user1 and user2 and use them as prefixes:
<Document xmlns:user1="http://user1.com" xmlns:user2=xmlns="http://user2.com">
<user1:user name="">
<login></login>
<password></password>
</user>
<user2:user name="">
<cert></cert>
</user>
</Document>
This way definition of the XML is shorter and clear.
But remember that aliases are just helpers. XML parsers and validators always substitute aliases with the full namespace, like http://user1.com" or http://user2.com for tag comparison.
In your example, adding xmlns="something" redefines default namespace of the root element for XML default namespace to "something".
When JAXB tries to unmarshal your object, it's looking in the XML for the Document in the empty namespace and couldn't find it because Document is defined in the "something" namespace.
Upvotes: 2