7

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.

4

1 回答 1

10

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
于 2013-01-09T11:40:01.127 回答