Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB - how to unmarshall this XML?

Tags:

java

xml

jaxb

Theres some pretty nasty XML that i'd like to unmarshall to a java object using JaxB. Most of it has seemed quite straightforward so far - but I am kinda stuck on this:

            <assets>
                <asset type="fixed">74,414</asset>
                <asset type="current">1,022,069</asset>
                <asset type="other">0</asset>
                <total type="assets">1,096,483</total>
            </assets>

This is the relevant part of the dtd

<!ELEMENT assets (asset|total)*> <!ELEMENT asset (#PCDATA)> <!ATTLIST asset type CDATA #REQUIRED> <!ELEMENT total (#PCDATA)> <!ATTLIST total type CDATA #REQUIRED>

Any ideas? Or should I give up trying to use JAXB for this?

Thanks

like image 343
Andrew B Avatar asked Jul 08 '10 17:07

Andrew B


People also ask

How do you Unmarshal XML?

To unmarshal an xml string into a JAXB object, you will need to create an Unmarshaller from the JAXBContext, then call the unmarshal() method with a source/reader and the expected root object.

How does JAXB read XML?

To read XML, first get the JAXBContext . It is entry point to the JAXB API and provides methods to unmarshal, marshal and validate operations. Now get the Unmarshaller instance from JAXBContext . It's unmarshal() method unmarshal XML data from the specified XML and return the resulting content tree.

What is XML Marshalling?

Object/XML Mapping, or O/X mapping for short, is the act of converting an XML document to and from an object. This conversion process is also known as XML Marshalling, or XML Serialization.

What is JAXB marshalling and Unmarshalling?

JAXB definitionsMarshalling is the process of transforming Java objects into XML documents. Unmarshalling is the process of reading XML documents into Java objects. The JAXBContext class provides the client's entry point to the JAXB API. It provides API for marshalling, unmarshalling and validating.


2 Answers

Looking at the XML and the DTD, I created the XSD of the structure:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  elementFormDefault="qualified">
  <xs:element name="assets">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" ref="asset"/>
        <xs:element maxOccurs="unbounded" ref="total"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="asset">
    <xs:complexType mixed="true">
      <xs:attribute name="type" use="required" type="xs:string"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="total">
    <xs:complexType mixed="true">
      <xs:attribute name="type" use="required" type="xs:string"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

Use xjc to generate the Java classes annotated with the JAXB binding annotations from the XSD. Then use the unmarshaller to unmarshal it to Java object.

Edit

Generated Java classes:

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;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "asset",
    "total"
})
@XmlRootElement(name = "assets")
public class Assets {

    @XmlElement(required = true)
    protected List<Asset> asset;
    @XmlElement(required = true)
    protected List<Total> total;

    public List<Asset> getAsset() {
        if (asset == null) {
            asset = new ArrayList<Asset>();
        }
        return this.asset;
    }

    public List<Total> getTotal() {
        if (total == null) {
            total = new ArrayList<Total>();
        }
        return this.total;
    }

}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "content"
})
@XmlRootElement(name = "asset")
public class Asset {

    @XmlValue
    protected String content;
    @XmlAttribute(required = true)
    protected String type;

    public String getContent() {
        return content;
    }

    public void setContent(String value) {
        this.content = value;
    }

    public String getType() {
        return type;
    }

    public void setType(String value) {
        this.type = value;
    }

}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "content"
})
@XmlRootElement(name = "total")
public class Total {

    @XmlValue
    protected String content;
    @XmlAttribute(required = true)
    protected String type;

    public String getContent() {
        return content;
    }

    public void setContent(String value) {
        this.content = value;
    }

    public String getType() {
        return type;
    }

    public void setType(String value) {
        this.type = value;
    }

}
like image 112
Abhinav Sarkar Avatar answered Nov 09 '22 06:11

Abhinav Sarkar


Do you have a class you are unmarshalling to? It sounds like it would need the following:

/** AssetContainer */
@XmlRootElement(namespace = "project/schema")
@XmlAccessorType(XmlAccessType.FIELD)
public class AssetContainer implements Unmarshallable {
    private List<Asset> assetList;
    private int totalAssets;
}

/** Asset */
@XmlType
@XmlAccessorType(XmlAccessType.FIELD)
public class Asset implements Unmarshallable {
    private AssetTypeEnum type;
    private int count;
}

/** Unmarshallable */
public interface Unmarshallable {
    // Marker interface
}

And then use an XmlTypeAdapter to map the XML elements to the proper class.

like image 42
Andy Avatar answered Nov 09 '22 08:11

Andy