Unmarshal nested XML elements with JAXB

徘徊边缘 提交于 2021-01-24 11:22:57

问题


I'm starting with JAXB and im trying to read the following xml to map it to a classe:

<element id="0">
        <type>1</type>
        <color>0</color>
        <size>1</size>
        <location>
          <absolute>
            <absolute-item>top</absolute-item>
            <absolute-item>left</absolute-item>
          </absolute>
          <relative>
            <right>0</right>
            <left>0</left>            
          </relative>
        </location>
    </element>

My porblem comes when I try to map the nested elements like abslute, wich can contain any number of elements. I'm trying this right now:

public class Element {
    @XmlAttribute
    private int id;
    @XmlElement
    private int type;
    @XmlElement
    private int color;
    @XmlElement
    private int size;
    @XmlElementWrapper(name="absolute")
    @XmlElement(name="absolute-item")
    private ArrayList<String> absoluteItems;

    @Override
    public String toString() {
        return "Element "+id+" {" +
                "type=" + type +
                ", color=" + color +
                ", size=" + size +
                ", Location Relative: "+ absoluteItems
                +"}";
    }
}

I got the simple elements but not the nested one. Apparently I can't annotate to wrappers together, so I don't know how to fix it.

UPDATE: I'm trying this as suggested. I'm getting an IllegalAnnotationExceptions because Element$Location.right is not a compilation property, but i don't know what it means. Should I create one more class for the element?

public class Element {
    @XmlAttribute
    private int id;
    @XmlElement
    private int type;
    @XmlElement
    private int color;
    @XmlElement
    private int size;

    @XmlElement(name="location")
    private Location location;

    public static class Location {
        @XmlElementWrapper(name="absolute")
        @XmlElement(name="absolute-item")
        private ArrayList<String> absoluteItems;


        @XmlElementWrapper(name="relative")
        @XmlElement(name="right")
        private int right;
        @XmlElement(name="left")
        private int left;

        @Override
        public String toString() {
            return "Location{" +
                    "Absolute=" + absoluteItems +
                    ", relative {right=" + right +
                    ", left=" + left +
                    "}}";
        }
    }

回答1:


JAXB processing assumes a separate element definition for each complex element. A complex element means an element containing other elements.

The error you mention, referring to Element$Location, probably indicates the jaxb routines have found the annotation for the field "right" in the nested Location class; at runtime, nested classes have the name of the containing class, in this case Element, as a prefix separated from the nested class by a dollar sign.

To unmarshall (translate from xml text to Java code) the data structure you provide above, the JAXB routines would expect to find the following public class definitions:

Absolute Element Location ObjectFactory Relative

In the java code the jaxb compiler produces, the main element definition has its own class, and the following annotations:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
   "type",
    "color",
    "size",
    "location"
})
@XmlRootElement(name = "element")
public class Element 
{
   @XmlElement(required = true)
   protected BigInteger type;
      .
      .   additional element definitions go here
      . 
   // note: location here is a public class
   @XmlElement(required = true)
   protected Location location;
   // the attribute is defined thus:
   @XmlAttribute(name = "id")
   protected BigInteger id;

   /**
    * Gets the value of the type property.
    * @return BigInteger type code
    */
   public BigInteger getType() { return type; }

   /**
    * Sets the value of the type property.
    * @param value BigInteger type code to set
    */
   public void setType(BigInteger value) { this.type = value; }
      .
      . all other getters and setters defined here
      .
}

The element contained, in this case Location, has its own class with the following annotations:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Location", propOrder = {
   "absolute",
   "relative"
})
public class Location 
{
    protected Absolute absolute;
    protected Relative relative;
      .
      .  getters and setters go here: note these fields have no 
      .  annotations
}

Again, jaxb expects to find public Absolute and Relative classes. Since the absolute-item element can be repeated indefinitely, jaxb expects to find it defined as a collection (List), thus:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Absolute", propOrder = {
   "absoluteItem"
})
public class Absolute 
{
   @XmlElement(name = "absolute-item", required = true)
   protected List<String> absoluteItem;

   /**
    * Gets the value of the absoluteItem property.
    * 
    * <p>This accessor returns a reference to the live list; any
    * modification to the returned list will be reflected in the 
    * JAXB object.
    * This is why there is not a setter for absoluteItem.
    * 
    * To add a new item, do as follows:
    *    getAbsoluteItem().add(newItem)
    */
   public List<String> getAbsoluteItem() 
   {
      if (absoluteItem == null) 
          absoluteItem = new ArrayList <> ();        
      return this.absoluteItem;
   }

}

In my experience, jaxb schema compiler, xjc, provides the easiest way, by far, to generate classes or use with jaxb. xjc takes an XML schema definition, and translates it into java code for you; you then have only to include the resulting java files in your project. Most Java development tools will handle this for you automatically. To generate the code I used as a source for the examples above (I did some condensing, I wrote the following schema:

<?xml version="1.0" encoding="UTF-8"?>

<!--
  Component ==> example for stack overflow
  Purpose: show how the jaxb compiler works
 -->

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
           xmlns:desc = "http://sox.org/element"
           targetNamespace = "http://sox.org/element"
           jxb:version="2.0">

    <xs:element name="element">
       <xs:complexType>
          <xs:sequence>
             <xs:element name = "type" type = "xs:integer" />
             <xs:element name = "color" type = "xs:integer" />
             <xs:element name = "size" type = "xs:integer" />
             <xs:element name = "location" type = "desc:Location" />
          </xs:sequence>
          <xs:attribute name="id" type="xs:integer" use="optional"
                        default="0" />
       </xs:complexType>
    </xs:element>     

    <xs:complexType name="Location">
       <xs:sequence>
          <xs:element name = "absolute" type = "desc:Absolute" 
                      minOccurs="0" />
          <xs:element name = "relative" type = "desc:Relative" 
                      minOccurs="0" /> 
       </xs:sequence>
    </xs:complexType>

    <xs:complexType name="Absolute">
       <xs:sequence>
          <xs:element name="absolute-item" type="xs:string"  
                      maxOccurs="unbounded" />
       </xs:sequence>
    </xs:complexType> 

    <xs:complexType name="Relative">
       <xs:sequence>
          <xs:element name="right" type="xs:string" /> 
          <xs:element name="left" type="xs:string" /> 
       </xs:sequence>
    </xs:complexType>



来源:https://stackoverflow.com/questions/49181125/unmarshal-nested-xml-elements-with-jaxb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!