Tuesday, August 14, 2012

XML Serialization in Android

I needed XML serialization in Android badly. I had lot of schemas and I didn’t have the patience to parse the XML using Sax. You can use JAXB to marshal and unmarshal XML. Using XJC - the JAXB Binding compiler you can generate the java classes from your schema.

JAXB is not available for Android, because dalvik does not support Reflection.

But thanks to Simple XML ,  with few modifications of JAXB generated, I could entirely convert my xml to java class object.

The articles at simple xml site are really helpful.

Edited the schema book.xsd from msdn link as follows:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="catalog">

    <xs:complexType>

      <xs:sequence>

        <xs:element name ="book" type="Book" maxOccurs="unbounded"/>

      </xs:sequence>

    </xs:complexType>

  </xs:element>



  <xs:complexType name="Book">

    <xs:sequence>

      <xs:element name="author" type="xs:string"/>

      <xs:element name="title" type="xs:string"/>



      <xs:element name="price" type="xs:float"/>

      <xs:element name="description" type="xs:string"/>

      <xs:sequence>

        <xs:element name ="UserReview" type="UserReview" maxOccurs="unbounded"/>

      </xs:sequence>

    </xs:sequence>

    <xs:attribute name="id" type="xs:string"/>

    <xs:attribute name="genre" type="Genre"/>

  </xs:complexType>

 

  <xs:complexType name="Review">

    <xs:simpleContent>

      <xs:extension base="xs:string">

        <xs:attribute name="language" type="xs:string" />

      </xs:extension>

    </xs:simpleContent>

  </xs:complexType>



  <xs:complexType name="UserReview">

    <xs:sequence>

      <xs:element maxOccurs="1" name="Date" type="xs:string" />

      <xs:sequence>

        <xs:element name="Review" type="Review" minOccurs="0" maxOccurs="2" />

      </xs:sequence>

    </xs:sequence>

    <xs:attribute name="userid" type="xs:string" use="required" />

  </xs:complexType>



  <xs:simpleType name="Genre">

    <xs:restriction base="xs:string">

      <xs:enumeration value="Fiction"/>

      <xs:enumeration value="NonFiction"/>

      <xs:enumeration value="Children"/>

    </xs:restriction>

  </xs:simpleType>

 

</xs:schema>



Xjc.exe must be found in your JAVA_HOME/bin folder. Add the bin path to your system Path variable.

Now create the java classes from the book schema using xjc. For ex:

xjc -p in.blogspot.negabinary book.xsd

Add the generated package to your application source.

It’s time to replace the JAXB annotations with SimpleXML annotations.

Download Simple XML Serialization library from here

Copy the simple-xml-2.6.6.jar (found inside the folder simple-xml-2.6.6\jar) to your application source libs folder.

Remove all import javax.xml.bind.* from the generated sources. Edit your class sources like the table below:

(Note: this table does not contain all the replacements)

Original JAXB generated class
Replace with SimpleXML annotation
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "book"
})
@XmlRootElement(name = "catalog")
@Root
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Review", propOrder = {
    "value"
})
@Default
@XmlAttribute(name = "language")
    protected String language;
@Attribute(name = "language", required=false)
    protected String language;

Note: unless specified, required=true. Therefore you have to make required=false
@XmlElement(name = "Date", required = true)
    protected String date;
@Element(name = "Date", required = true)
    protected String date;
@XmlValue
    protected String value;
@Text(required=false)
@XmlElement(name = "UserReview", required = true)
        protected List<UserReview> userReview;
@ElementList(entry = "UserReview", inline = true)
        protected List<UserReview> userReview;

Note: ElementList is bit tricky. ‘name’ won’t work, ‘entry’ works.
@XmlType(name = "Genre")
@XmlEnum
public enum Genre {
I don’t know how to do.
Used String instead




Once you modify all your classes in SimpleXML format, its time to test your application.

A simple try as follows:

Catalog catalog ;

              try {

                     StringReader sr = new StringReader("<?xml version='1.0' encoding='utf-8'?> <catalog> <book id='id1' genre='Fiction'> <author>author1</author> <title>title1</title> <price>1</price> <description>description1</description> <UserReview userid='userid1'> <Date>Date1</Date> <Review language='language1'>Review1</Review> <Review language='language2'>Review2</Review> </UserReview> <UserReview userid='userid2'> <Date>Date2</Date> <Review language='language3'>Review3</Review> <Review language='language4'>Review4</Review> </UserReview> <UserReview userid='userid3'> <Date>Date3</Date> <Review language='language5'>Review5</Review> <Review language='language6'>Review6</Review> </UserReview> </book> <book id='id2' genre='NonFiction'> <author>author2</author> <title>title2</title> <price>-3.40282347E+38</price> <description>description2</description> <UserReview userid='userid4'> <Date>Date4</Date> <Review language='language7'>Review7</Review> <Review language='language8'>Review8</Review> </UserReview> <UserReview userid='userid5'> <Date>Date5</Date> <Review language='language9'>Review9</Review> <Review language='language10'>Review10</Review> </UserReview> <UserReview userid='userid6'> <Date>Date6</Date> <Review language='language11'>Review11</Review> <Review language='language12'>Review12</Review> </UserReview> </book> </catalog>") ;



                     Serializer serializer = new Persister();

                     catalog = serializer.read(Catalog.class, sr);

                     Log.v("TEST", catalog.getBook().get(0).getAuthor()) ;

              } catch (Exception e) {

                     e.printStackTrace();

              }

 That’s it folks.. !!


~Swarup