0

I am working on a XML file with multiple naespaces and I am trying ot unmarshal it. I have looked into some questions on stack overflow previously but have not yet met with the solution.

The XML file:

<?xml version="1.0" encoding="UTF-8"?>
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/ScoreVariant"> 
    <Student>
        <FirstName>RP</FirstName>
        <Value>
            <ms:String>Pass</ms:String>
        </Value>
    </Student>
    <Student>
        <FirstName>SK</FirstName>
        <Value>
            <ms:Int>100</ms:Int>
        </Value>
    </Student>
</Registry>

The Registry, Student class

@Data
@XmlRootElement(name="Registry")
@XmlAccessorType(XmlAccessType.FIELD)
public class Registry {
    @XmlElement
    private List<Student> Student;
}

Student:

@Data
@XmlAccessorType(XmlAccessType.FIELD)
//@XmlType(namespace = "http://www.registar.com/Grad")
public class Student {
    @XmlElement
    private String FirstName;
    private Value value; // suggestions to achieve this with different namespaces
}

I have a package-info.java file

@XmlSchema(
    namespace="http://www.registar.com", 
    elementFormDefault=XmlNsForm.QUALIFIED,
    xmlns={
            @XmlNs(prefix = "", namespaceURI = "http://www.registar.com"),
            @XmlNs(prefix = "ms",namespaceURI = "http://www.registar.com/Grad")
    }
)
@XmlAccessorType(XmlAccessType.FIELD)
import javax.xml.bind.annotation.*;

And i try to print out the unmarshalled entries. However the different namespaces are not recognised.

The output shows an error..

unexpected element (URI: "http://www.registar.com", local: "Registry"). Expected elements are <{} Registry>
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744)
    at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:262)
    at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:257)
    at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:124)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1149)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:574)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:556)
    at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:168)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:518)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3078)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:836)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:541)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1224)
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:258)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:229)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:170)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:209)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194)
    at Mainparser.main(Mainparser.java:20)

Could you please suggest or provide some guidance here?


Update: As per the suggestion, I passed the prefix of ns0 to the default namespace and made the changes. I do not get any error, but the output is not as expected

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Registry>
    <Student>
        <FirstName>RP</FirstName>
        <Value/>
    </Student>
    <Student>
        <FirstName>SK</FirstName>
        <Value/>
    </Student>
</Registry>

UPDATE2:

The xmlns:ms has the different scorevariants( it could be string or int or double).. I am not able to extract this information as well.. There needs to be a Value class, but I do not seem to find a way to extract the information


Update 3: The value class was written as per the suggestion.

@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Value {
    
     @XmlElements( value =  {
         @XmlElement(name="ms:String",type = String.class),
         @XmlElement(name="ms:Int",type = Integer.class)
     })
     private Object value;

}

The output is as below:

<Registry xmlns:ms="http://www.registar.com/ScoreVariant" xmlns="http://www.registar.com">
    <Student>
        <FirstName>RP</FirstName>
        <Value/>
    </Student>
    <Student>
        <FirstName>SK</FirstName>
        <Value/>
    </Student>
</Registry>

Rest of the code is the same.. Please suggest if there is any dependency that I am missing on..

2 Answers2

0

You would be able to achieve this by doing the following:

Your package-info.java

@XmlSchema(
        namespace = "http://www.registar.com",
        elementFormDefault = XmlNsForm.QUALIFIED,
        xmlns = {
                @XmlNs(prefix = "", namespaceURI = "http://www.registar.com"),
                @XmlNs(prefix = "", namespaceURI = "http://www.registar.com/Grad"),
                @XmlNs(prefix = "ms", namespaceURI = "http://www.registar.com/Value")
        }
)
@XmlAccessorType(XmlAccessType.FIELD)

Your Value class, which you did not provide here, so I made an assumption of how it would look like:

@XmlRootElement(name = "Value", namespace = "http://www.registar.com/Value")
@XmlAccessorType(XmlAccessType.FIELD)
public class Value {

    @XmlElement(name = "String", namespace = "http://www.registar.com/Value")
    private String string;

    @XmlElement(name = "Int", namespace = "http://www.registar.com/Value")
    private Integer number;
}

Once you do the Marshalling your XML will look like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/Value"
          xmlns:ns3="http://www.registar.com/Grad">
    <Student>
        <FirstName>RP</FirstName>
        <Value>
            <ms:String>Pass</ms:String>
        </Value>
    </Student>
    <Student>
        <FirstName>SK</FirstName>
        <Value>
            <ms:Int>100</ms:Int>
        </Value>
    </Student>
</Registry>

Here the namespace is registered and configured to have a prefix, subsequently we tell the fields in the Value class which namespace they're using.

My experience of the actual specs of SOAP are not sufficient to tell you whether this would be a valid SOAP. My testing however allowed for both marshalling and unmarshalling if this XML file.

BuzZin'
  • 441
  • 1
  • 5
  • 10
  • Hi, the Value class I have not added because I did not know how to extract the data. In the first student tag, the value is supposed to be a String, and it is extracted from ScoreVariant namespace. Ideally scorevariant is like a collection with different namespaces. In the 2nd Student tag, it is an Integer. So the value is 100.. Any suggestions to achieve this? – Rakshan Premsagar Kapikad Aug 20 '21 at 11:33
0

I believe this is something you are looking for:

XML:

<?xml version="1.0" encoding="UTF-8"?>
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/ScoreVariant">
    <Student>
        <FirstName>RP</FirstName>
        <Value>
            <ms:String>Pass</ms:String>
        </Value>
    </Student>
    <Student>
        <FirstName>SK</FirstName>
        <Value>
            <ms:Int>100</ms:Int>
        </Value>
    </Student>
</Registry>

Registry:

@XmlRootElement(name = "Registry")
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Registry {
    @XmlElement(name = "Student")
    List<Student> Student;
}

Student:

@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Student {
    @XmlElement(name="FirstName")
    private String FirstName;
    private Value Value;
}

Value:

@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Value {

   @XmlElements({
            @XmlElement(name = "ms:String", type = String.class),
            @XmlElement(name = "ms:Int", type = Integer.class)
    })
    private Object value;
}

package-info.java:

@XmlSchema(
        elementFormDefault = XmlNsForm.QUALIFIED,
        namespace = "http://www.registar.com",
        xmlns = {@XmlNs(prefix = "", namespaceURI = "http://www.registar.com"),
                @XmlNs(prefix = "ms", namespaceURI = "http://www.registar.com/ScoreVariant")})
package stackover;

import jakarta.xml.bind.annotation.XmlNs;
import jakarta.xml.bind.annotation.XmlNsForm;
import jakarta.xml.bind.annotation.XmlSchema;

Main:

public class Main {
    public static void main(String[] args) throws JAXBException, XMLStreamException {
        final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("sample.xml");
        final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
        final Unmarshaller unmarshaller = JAXBContext.newInstance(Registry.class).createUnmarshaller();
        final Registry registry = unmarshaller.unmarshal(xmlStreamReader, Registry.class).getValue();
        System.out.println(registry.toString());

        Marshaller marshaller = JAXBContext.newInstance(Registry.class).createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(registry, System.out);
    }
}

package-info.java

@XmlSchema(
    
    namespace="http://www.registar.com",
    xmlns={
            @XmlNs(prefix = "",namespaceURI = "http://www.registar.com"),
            @XmlNs(prefix = "ms",namespaceURI = "http://www.registar.com/ScoreVariant")
    },
    
    elementFormDefault=XmlNsForm.QUALIFIED
)package code;

//@XmlAccessorType(XmlAccessType.FIELD)



import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Registry(Student=[Student(FirstName=RP, Value=Value(value=Pass)), Student(FirstName=SK, Value=Value(value=100))])
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/ScoreVariant">
   <Student>
      <FirstName>RP</FirstName>
      <Value>
         <ms:String>Pass</ms:String>
      </Value>
   </Student>
   <Student>
      <FirstName>SK</FirstName>
      <Value>
         <ms:Int>100</ms:Int>
      </Value>
   </Student>
</Registry>
BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98