New to JAXB, I am trying to unmarshall XML document. I used the xjc
command to build the DataSet and ObjectFactory from the XSD file:
<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="NewDataSet">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Table">
<xs:complexType>
<xs:sequence>
<xs:element name="AUTHOR" type="xs:string" minOccurs="0"/>
<xs:element name="TITLE" type="xs:string" minOccurs="0"/>
<xs:element name="ISBN" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
The NewDataSet
class generated is as follows:
package generated;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"table"
})
@XmlRootElement(name = "NewDataSet")
public class NewDataSet {
@XmlElement(name = "Table")
protected List<NewDataSet.Table> table;
public List<NewDataSet.Table> getTable() {
if (table == null) {
table = new ArrayList<NewDataSet.Table>();
}
return this.table;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"author",
"title",
"isbn"
})
public static class Table {
@XmlElement(name = "AUTHOR")
protected String author;
@XmlElement(name = "TITLE")
protected String title;
@XmlElement(name = "ISBN")
protected String isbn;
public String getAUTHOR() {
return author;
}
public void setAUTHOR(String value) {
this.author = value;
}
public String getTITLE() {
return title;
}
public void setTITLE(String value) {
this.title = value;
}
public String getISBN() {
return isbn;
}
public void setISBN(String value) {
this.isbn = value;
}
}
}
The ObjectFactory
is:
package generated;
import javax.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public NewDataSet createNewDataSet() {
return new NewDataSet();
}
public NewDataSet.Table createNewDataSetTable() {
return new NewDataSet.Table();
}
}
The XML file that I am trying to unmarshall is as follows:
<NewDataSet xmlns="">
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<Table diffgr:id="Table1" msdata:rowOrder="0">
<AUTHOR>Kubo Tite</AUTHOR>
<TITLE>Bleach</TITLE>
<ISBN>1234456</ISBN>
</Table>
<Table diffgr:id="Table2" msdata:rowOrder="2">
<AUTHOR>Masashi Kishimoto</AUTHOR>
<TITLE>Naruto</TITLE>
<ISBN>435345</ISBN>
</Table>
<Table diffgr:id="Table3" msdata:rowOrder="3">
<AUTHOR>Eiichiro Oda</AUTHOR>
<TITLE>One Piece</TITLE>
<ISBN>56767</ISBN>
</Table>
</diffgr:diffgram>
</NewDataSet>
The code that does the unmarshalling is as follows:
package consume;
import generated.NewDataSet;
import generated.NewDataSet.Table;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class UnmarshallingCode {
public static void main(String[] args) {
try{
File file=new File("data.xml");
JAXBContext jb=JAXBContext.newInstance(NewDataSet.class);
Unmarshaller unmarshaller=jb.createUnmarshaller();
NewDataSet newDataSet=(NewDataSet)unmarshaller.unmarshal(file);
for(Table t: newDataSet.getTable()){
System.out.println(t.getTITLE());
}
}catch(JAXBException e){
e.printStackTrace();
}
}
}
The above code doesn't generate any errors but isn't producing any result. The call newDataSet.getTable()
returns an empty list.
However if I remove the <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
and its related attributes from the XML file, the above code runs fine and produces all the titles in the XML document. But that is not a permissible solution as the XML document is very large and most probably I am not allowed to make huge changes to the structure. How can I unmarshall the above mentioned XML file? Please advice.
To unmarshal an XML string into a JAXB object, just inject the Jaxb2Marshaller and call the unmarshal() method.
Using the Runtime Binding Framework. The Java™ Architecture for XML Binding (JAXB) provides an API and tools that automate the mapping between XML documents and Java objects. The JAXB framework enables developers to perform the following operations: Unmarshal XML content into a Java representation.
JAXB stands for Java Architecture for XML Binding. It provides mechanism to marshal (write) java objects into XML and unmarshal (read) XML into object. Simply, you can say it is used to convert java object into xml and vice-versa.
The XML document you are trying to unmarshal does not conform to your XML schema. This is why your JAXB (JSR-222) implementation is not bringing in the data as your expect, and why it does when you remove the diffgr
element.
Removing the Extra Element
You could create a filtered XMLStreamReader
that removes the extra elements and then unmarshal from that.
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource("src/forum14234091/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
xsr = xif.createFilteredReader(xsr, new StreamFilter() {
@Override
public boolean accept(XMLStreamReader xsr) {
if(xsr.isStartElement() || xsr.isEndElement()) {
return !"urn:schemas-microsoft-com:xml-diffgram-v1".equals(xsr.getNamespaceURI());
}
return true;
}
});
Creating the JAXBContext
When you generate a JAXB model from an XML schema you should create the JAXBContext
on the package name of the generated classes and not the root class. This will ensure that all the generated artifacts get processed.
JAXBContext jb=JAXBContext.newInstance("generated");
Unmarshaller unmarshaller=jb.createUnmarshaller();
NewDataSet newDataSet=(NewDataSet)unmarshaller.unmarshal(xsr);
for(Table t: newDataSet.getTable()){
System.out.println(t.getTITLE());
}
Changing the Package Name
By default the package name of generated classes is based on the targetNamespace
and is generated
if there isn't one. You can also specify the package name during the XJC call.
xjc -p com.example.foo schema.xsd
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