Pregunta

I have some XML-files that have the following structure:

<?xml version="1.0" encoding="iso-8859-1"?>
<ROOT xmlns="http://www.XXX.com/YYY"
    xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
    <DOCUMENT>
        <title>Doc 1</title>
    </DOCUMENT>
    <DOCUMENT>
        <title>Doc 2</title>
    </DOCUMENT>
    <TEXT>
        <content>Text 1</content>
    </TEXT>
    <TEXT>
        <content>Text 2</content>
    </TEXT>
    <ITEM>
        <id>1</id>
    </ITEM>
    <ITEM>
        <id>2</id>
    </ITEM>
</ROOT>

I want to parse the files using JAXB and thus I have to create models for all the elements. But what would the model for the ROOT element be? Is it allowed in XML to put different datatypes in one list?

I called my model DocumentList but what is the generic type of my list? Can I do it with one list or do I have have to create different lists?

@XmlRootElement(name = "ROOT")
public class DocumentList {

    private List elements;

}

Thanks in advance!

Update

My model classes look like this:

@XmlRootElement(name = "ROOT")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {

    @XmlElement(name = "DOCUMENT")
    private List<Document> documents;

    @XmlElement(name = "TEXT")
    private List<Text> texts;

    @XmlElement(name = "ITEM")
    private List<Item> items;

}

@XmlRootElement(name = "DOCUMENT")
@XmlAccessorType(XmlAccessType.FIELD)
public class Document {

    @XmlElement(name = "title")
    private String title;

}

@XmlRootElement(name = "TEXT")
@XmlAccessorType(XmlAccessType.FIELD)
public class Text {

    @XmlElement(name = "content")
    private String content;

}

@XmlRootElement(name = "ITEM")
@XmlAccessorType(XmlAccessType.FIELD)
public class Item {

    @XmlElement(name = "id")
    private String id;

}

Getters and setters are implemented, too.

Now I get the following exception:

javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.XXX.com/YYY", local:"ROOT"). Expected elements are <{}DOCUMENT>,<{}TEXT>,<{}ITEM>,<{}ROOT>
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(Unknown Source)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
    at com.siemens.xmlmerger.Test.main(Test.java:53)

Why does it expect <{}ROOT>? And what am I doing wrong?

¿Fue útil?

Solución 2

I'd use three different lists (one for each type).

@XmlRootElement(name = "ROOT")
public class DocumentList {

    @XmlElement(name="DOCUMENT")
    private List documents;

    @XmlElement(name="TEXT")
    private List texts;

    @XmlElement(name="ITEMS")
    private List items;

}

Otros consejos

There are couple of different ways to support this use case if you want to represent it as a single list (see below). You could also represent it as separate lists.

OPTION #1 - Each Element Corresponds to a Unique Class

If each element name in your list corresponds to a different class, then you can use one List by leveraging @XmlElements and doing the following:

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "ROOT")
@XmlAccessorType(XmlAccessType.FIELD)
public class DocumentList {

    @XmlElements({
       @XmlElement(name="DOCUMENT", type=Document.class),
       @XmlElement(name="TEXT", type=Text.class),
       @XmlElement(name="ITEM", type=Item.class)
    })
    private List elements;

}

OPTION #2- Multiple Elements Correspond to the Same Class

If the Class of the entry in the List is not enough to uniquely map it to an element, then you are going to need to leverage JAXBElement to maintain the element information. Note how we have we have removed the @XmlElements annotation and replaced it with @XmlElementRefs.

import java.util.List;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "ROOT")
@XmlAccessorType(XmlAccessType.FIELD)
public class DocumentList {

    @XmlElementRefs({
       @XmlElementRef(name="DOCUMENT", type=JAXBElement.class),
       @XmlElementRef(name="TEXT", type=JAXBElement.class),
       @XmlElementRef(name="ITEM", type=JAXBElement.class)
    })
    private List elements;

}

Along with the @XmlElementRefs/@XmlElementRef annotations we need to provide @XmlElementDecl annotations on a class annotated with @XmlRegistry.

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

    @XmlElementDecl(name="DOCUMENT")
    public JAXBElement<String> createDocument(String value) {
        return new JAXBElement<String>(new QName("DOCUMENT"), String.class, value);
    }

    @XmlElementDecl(name="TEXT")
    public JAXBElement<String> createText(String value) {
        return new JAXBElement<String>(new QName("TEXT"), String.class, value);
    }

    @XmlElementDecl(name="ITEM")
    public JAXBElement<String> createItem(String value) {
        return new JAXBElement<String>(new QName("ITEM"), String.class, value);
    }

}

The elements in the xml will be mapped into attributes of the binding class

so

@XmlRootElement(name = "ROOT")
public class DocumentList {

    @XmlElement(name="DOCUMENT")
    private List documents;

    @XmlElement(name="TEXT")
    private List texts;

    @XmlElement(name="ITEMS")
    private List items;

In above class attributes are mapped with list of elements in xml.

I hope you understand

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top