3

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;
}

1 Answers1

2

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.

Pavel Molchanov
  • 2,299
  • 1
  • 19
  • 24
  • and does the xmlns:xsi go inside the class ? thank you! –  Jun 19 '18 at 18:47
  • Im still facing the problem. Do you think its with `xmlns:xsi` ? thank you! –  Jun 19 '18 at 18:57
  • You can define many namespaces in the root element. xmlns is a default namespace, all elements without prefix will be defined in this namespace. xmlns:xsi defines the namespace for the XML Schema. If your XML is validated against the schema, xmlns:xsi will be used. – Pavel Molchanov Jun 19 '18 at 19:01
  • Be sure that namespace="some value" matches – Pavel Molchanov Jun 19 '18 at 19:48
  • Does not work if Im having both xmlns:xsi and xmlns in the root tag of the xml tree! –  Jun 19 '18 at 21:44
  • Yes you are right. I could parse but however the inner XML elements are being NULL. Not sure why but this was seen across multiple people where the inner elements are set to null. I tried to put the same namespace to those inner elements as well but failed. Is there anything that Im missing. Thank you! –  Jun 20 '18 at 03:59
  • Paste the full XML that you are trying to parse. – Pavel Molchanov Jun 20 '18 at 13:10