Sunday, 7 November 2010

Taming XStream part 3

The final part of this series will detail my attempt to deserialise an arbitary sample XML file into Java objects. I have selected the following RSS feed XML file:


<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title>Sample Channel</title> 
        <link>http://www.playstation.com/manual/psp/rss/</link> 
        <description>Contains sample content</description> 
        <language>en-us</language>
        <image>
            <url>http://www.playstation.com/manual/psp/rss/sample_ch.jpg</url>
            <title>Sample Channel</title>
        </image>
        <copyright>&#xA9; 2005 Sony Computer Entertainment Inc. All rights reserved.</copyright>
        <item>
            <title>HOUSE SAMPLE 1</title> 
            <link>http://www.playstation.com/manual/psp/rss/</link> 
            <description>HOUSE SAMPLE 1 / PSP Mix</description>
            <author>Noburo Masuda</author>
            <pubDate>Tue, 29 Nov 2005 15:00:00 +0900</pubDate> 
            <enclosure url="http://fj00.psp.update.playstation.org/media/HOUSE_SAMPLE_1.mp3" type="audio/mp3" /> 
        </item>
        <item>
            <title>JAZZ FUSION SAMPLE 1</title> 
            <link>http://www.playstation.com/manual/psp/rss/</link> 
            <description>JAZZ FUSION SAMPLE 1 / PSP Mix</description>
            <author>Noburo Masuda</author>
            <pubDate>Tue, 29 Nov 2005 14:00:00 +0900</pubDate>
            <enclosure url="http://fj00.psp.update.playstation.org/media/JAZZ_FUSION_SAMPLE_1.mp3" type="audio/mp3" /> 
        </item>
        <item>
            <title>Sample Video Clip</title> 
            <link>http://www.playstation.com/manual/psp/rss/</link> 
            <description>Sample Clip for RSS ch</description>
            <author>Sony Computer Entertainment Inc.</author>
            <pubDate>Thu, 27 Jul 2006 15:00:00 +0900</pubDate>
            <enclosure url="http://fj00.psp.update.playstation.org/media/SampleVideoClip.mp4" type="video/mp4" /> 
    <media:thumbnail url="http://fj00.psp.update.playstation.org/media/SampleVideoClip_tn.jpg" width="60" height="45"/>
        </item>
    </channel>
</rss>

This example includes collections of sub types, attributes and fields. We will need to create a class hierarchy which looks like RSS -> Channel -> Item. Then complete the appropriate field and attribute mapping as required. The following is the structure I have decided on:


private static class RSS {
private Channel channel;
public RSS(Channel channel) {
this.channel = channel;
}
}

private static class Channel {
String title;
String link;
String description;
String language;
Image image;
String copyright;
List<Item> items;
}

private static class Image {
String url;
String title;
}

private static class Item {
String title;
String link;
String description;
String author;
String pubDate;
Enclosure enclosure;
Thumbnail thumbnail;
}

private static class Enclosure {
String url;
String type;
}

private static class Thumbnail {
String url;
int width;
int height;
}

The following is the completed code listing which correctly deserialises the XML:


package xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import java.util.List;

public class Three {
public static void main(String [] args) {
XStream xstream = new XStream(new DomDriver());

// RSS
xstream.alias("rss", RSS.class);

// Channel
xstream.alias("channel", Channel.class);
xstream.addImplicitCollection(Channel.class, "items", "item", Item.class);

// Item
xstream.alias("enclosure", Enclosure.class);
xstream.alias("media:thumbnail", Thumbnail.class);
xstream.aliasField("media:thumbnail", Item.class, "thumbnail");

// Enclosure
xstream.aliasAttribute(Enclosure.class, "type", "type");
xstream.aliasAttribute(Enclosure.class, "url", "url");

// Thumbnail
xstream.aliasAttribute(Thumbnail.class, "url", "url");
xstream.aliasAttribute(Thumbnail.class, "width", "width");
xstream.aliasAttribute(Thumbnail.class, "height", "height");


RSS data = (RSS) xstream.fromXML(
One.class.getResourceAsStream("sample_ch.xml"));

System.out.println(data.toString());
}

private static class RSS {
private Channel channel;
public RSS(Channel channel) {
this.channel = channel;
}

@Override
public String toString() {
return channel.toString();
}
}

private static class Channel {
String title;
String link;
String description;
String language;
Image image;
String copyright;
List<Item> items;

@Override
public String toString() {
String r = "";
r += "title: " + title + "\n";
r += "description: " + description + "\n";
r += "image: " + image.toString() + "\n";
r += "copyright: " + copyright + "\n";
for (Item item : items) {
r += "\n";
r += item.toString() + "\n";
}
return r;
}
}

private static class Image {
String url;
String title;

@Override
public String toString() {
return title + " (" + url + ")";
}
}

private static class Item {
String title;
String link;
String description;
String author;
String pubDate;
Enclosure enclosure;
Thumbnail thumbnail;

@Override
public String toString() {
String r = "";
r += "title: " + title + "\n";
r += "description: " + description + "\n";
r += "link: " + link + "\n";
r += "pubDate: " + pubDate + "\n";

if (enclosure != null) {
r += enclosure.toString() + "\n";
}

if (thumbnail != null) {
r += thumbnail.toString() + "\n";
}

return r;
}
}

private static class Enclosure {
String url;
String type;

@Override
public String toString() {
return url + " (" + type + ")";
}
}

private static class Thumbnail {
String url;
int width;
int height;

@Override
public String toString() {
return url + " (" + width + "x" + height + ")";
}
}
}

No comments:

Post a Comment