Java Model
Weather Report
package blog.weather;
import java.util.List;
public class WeatherReport {
private String location;
private int currentTemperature;
private String currentCondition;
private List<Forecast> forecast;
}
Forecast
package blog.weather;
public class Forecast {
private String dayOfTheWeek;
private int low;
private int high;
private String condition;
}
Google Weather API
First we will leverage Google's Weather API. The following URL will be used to access the weather data for Ottawa, Canada:
The following is the result of performing the above query at time I was writing this article. I have highlighted the portions of the XML document that we will map to:
<xml_api_reply version="1">
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1"
row="0" section="0">
<forecast_information>
<city data="Ottawa, ON" />
<postal_code data="Ottawa" />
<latitude_e6 data="" />
<longitude_e6 data="" />
<forecast_date data="2011-09-08" />
<current_date_time data="2011-09-08 14:00:00 +0000" />
<unit_system data="US" />
</forecast_information>
<current_conditions>
<condition data="Mostly Cloudy" />
<temp_f data="66" />
<temp_c data="19" />
<humidity data="Humidity: 73%" />
<icon data="/ig/images/weather/mostly_cloudy.gif" />
<wind_condition data="Wind: NE at 13 mph" />
</current_conditions>
<forecast_conditions>
<day_of_week data="Thu" />
<low data="55" />
<high data="75" />
<icon data="/ig/images/weather/cloudy.gif" />
<condition data="Cloudy" />
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Fri" />
<low data="46" />
<high data="77" />
<icon data="/ig/images/weather/mostly_sunny.gif" />
<condition data="Partly Sunny" />
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Sat" />
<low data="43" />
<high data="68" />
<icon data="/ig/images/weather/sunny.gif" />
<condition data="Clear" />
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Sun" />
<low data="55" />
<high data="75" />
<icon data="/ig/images/weather/sunny.gif" />
<condition data="Clear" />
</forecast_conditions>
</weather>
</xml_api_reply>
Java Model - Mapped to Google's XML Schema via Annotations
We will map the result of the Google weather API via a combination of standard JAXB and MOXy extension annotations.
Weather Report
package blog.weather;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlRootElement(name="xml_api_reply")
@XmlType(propOrder={"location", "currentCondition", "currentTemperature", "forecast"})
@XmlAccessorType(XmlAccessType.FIELD)
public class WeatherReport {
@XmlPath("weather/forecast_information/city/@data")
private String location;
@XmlPath("weather/current_conditions/temp_f/@data")
private int currentTemperature;
@XmlPath("weather/current_conditions/condition/@data")
private String currentCondition;
@XmlPath("weather/forecast_conditions")
private List<Forecast> forecast;
}
Forecast
package blog.weather;
import org.eclipse.persistence.oxm.annotations.XmlPath;
public class Forecast {
@XmlPath("day_of_week/@data")
private String dayOfTheWeek;
@XmlPath("low/@data")
private int low;
@XmlPath("high/@data")
private int high;
@XmlPath("condition/@data")
private String condition;
}
Specify MOXy as the JAXB Provider (jaxb.properties)
To configure MOXy as your JAXB provider simply add a file named jaxb.properties in the same package as your domain model with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactoryFor more information see: Specifying EclipseLink MOXy as Your JAXB Provider.Demo
The following demo code will read the XML data for Google's weather service, and marshal the objects back to XML:
package blog.weather;
import java.net.URL;
import javax.xml.bind.*;
public class GoogleDemo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(WeatherReport.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
URL url = new URL("http://www.google.com/ig/api?weather=Ottawa");
WeatherReport weatherReport = (WeatherReport) unmarshaller.unmarshal(url);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(weatherReport, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<xml_api_reply>
<weather>
<forecast_information>
<city data="Ottawa, ON"/>
</forecast_information>
<current_conditions>
<condition data="Mostly Cloudy"/>
<temp_f data="68"/>
</current_conditions>
<forecast_conditions>
<day_of_week data="Thu"/>
<low data="55"/>
<high data="75"/>
<condition data="Cloudy"/>
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Fri"/>
<low data="46"/>
<high data="77"/>
<condition data="Partly Sunny"/>
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Sat"/>
<low data="43"/>
<high data="68"/>
<condition data="Clear"/>
</forecast_conditions>
<forecast_conditions>
<day_of_week data="Sun"/>
<low data="55"/>
<high data="75"/>
<condition data="Clear"/>
</forecast_conditions>
</weather>
</xml_api_reply>
Yahoo Weather API
The following URL will be used to access the weather data for Ottawa using the Yahoo Weather API (3369 is the WOEID for Ottawa):
The following is the result of performing the above query at time I was writing this article:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0"
xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
<channel>
<title>Yahoo! Weather - Ottawa, CA</title>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/Ottawa__CA/*http://weather.yahoo.com/forecast/CAXX0343_f.html</link>
<description>Yahoo! Weather for Ottawa, CA</description>
<language>en-us</language>
<lastBuildDate>Thu, 08 Sep 2011 10:58 am EDT</lastBuildDate>
<ttl>60</ttl>
<yweather:location city="Ottawa" region="ON"
country="Canada" />
<yweather:units temperature="F" distance="mi" pressure="in"
speed="mph" />
<yweather:wind chill="66" direction="40" speed="12" />
<yweather:atmosphere humidity="73" visibility=""
pressure="30.14" rising="0" />
<yweather:astronomy sunrise="6:31 am" sunset="7:25 pm" />
<image>
<title>Yahoo! Weather</title>
<width>142</width>
<height>18</height>
<link>http://weather.yahoo.com</link>
<url>http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif</url>
</image>
<item>
<title>Conditions for Ottawa, CA at 10:58 am EDT</title>
<geo:lat>45.42</geo:lat>
<geo:long>-75.69</geo:long>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/Ottawa__CA/*http://weather.yahoo.com/forecast/CAXX0343_f.html</link>
<pubDate>Thu, 08 Sep 2011 10:58 am EDT</pubDate>
<yweather:condition text="Mostly Cloudy" code="28"
temp="66" date="Thu, 08 Sep 2011 10:58 am EDT" />
<description><![CDATA[
<img src="http://l.yimg.com/a/i/us/we/52/28.gif"/><br />
<b>Current Conditions:</b><br />
Mostly Cloudy, 66 F<BR />
<BR /><b>Forecast:</b><BR />
Thu - Partly Cloudy. High: 75 Low: 57<br />
Fri - Partly Cloudy. High: 79 Low: 53<br />
<br />
<a href="http://us.rd.yahoo.com/dailynews/rss/weather/Ottawa__CA/*http://weather.yahoo.com/forecast/CAXX0343_f.html">Full Forecast at Yahoo! Weather</a><BR/><BR/>
(provided by <a href="http://www.weather.com" >The Weather Channel</a>)<br/>
]]></description>
<yweather:forecast day="Thu" date="8 Sep 2011" low="57"
high="75" text="Partly Cloudy" code="30" />
<yweather:forecast day="Fri" date="9 Sep 2011" low="53"
high="79" text="Partly Cloudy" code="30" />
<guid isPermaLink="false">CAXX0343_2011_09_09_7_00_EDT</guid>
</item>
</channel>
</rss><!-- api4.weather.sp2.yahoo.com uncompressed/chunked Thu Sep 8 08:32:54
PDT 2011 -->
Java Model - Mapped to Yahoo's XML Schema via XML Metadata
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="blog.weather"
xml-mapping-metadata-complete="true">
<xml-schema element-form-default="QUALIFIED">
<xml-ns prefix="yweather" namespace-uri="http://xml.weather.yahoo.com/ns/rss/1.0"/>
</xml-schema>
<java-types>
<java-type name="WeatherReport" xml-accessor-type="FIELD">
<xml-root-element name="rss"/>
<xml-type prop-order="location currentTemperature currentCondition forecast"/>
<java-attributes>
<xml-attribute java-attribute="location" xml-path="channel/yweather:location/@city"/>
<xml-attribute java-attribute="currentTemperature" name="channel/item/yweather:condition/@temp"/>
<xml-attribute java-attribute="currentCondition" name="channel/item/yweather:condition/@text"/>
<xml-element java-attribute="forecast" name="channel/item/yweather:forecast"/>
</java-attributes>
</java-type>
<java-type name="Forecast" xml-accessor-type="FIELD">
<java-attributes>
<xml-attribute java-attribute="dayOfTheWeek" name="day"/>
<xml-attribute java-attribute="low"/>
<xml-attribute java-attribute="high"/>
<xml-attribute java-attribute="condition" name="text"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Demo
The following demo code will read the XML data for Yahoo's weather service, and marshal the objects back to XML. Due to a MOXy bug regarding unmapped CDATA sections (https://bugs.eclipse.org/357145, this bug has been fixed in EclipseLink 2.3.1), a filtered XMLStreamReader was used to remove it from the XML input:
package blog.weather;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.StreamFilter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class YahooDemo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "blog/weather/yahoo-binding.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {WeatherReport.class}, properties);
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource("http://weather.yahooapis.com/forecastrss?w=3369");
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
xsr = xif.createFilteredReader(xsr, new CDATAFilter());
Unmarshaller unmarshaller = jc.createUnmarshaller();
WeatherReport weatherReport = (WeatherReport) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(weatherReport, System.out);
}
private static class CDATAFilter implements StreamFilter {
public boolean accept(XMLStreamReader xsr) {
return XMLStreamReader.CDATA != xsr.getEventType();
}
}
}
Output
Below is the result of running the demo code. The output represents the portion of the XML document that we had mapped to:
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0">
<channel>
<yweather:location city="Ottawa"/>
<item>
<yweather:forecast day="Thu" low="57" high="74" text="Partly Cloudy"/>
<yweather:forecast day="Fri" low="53" high="79" text="Partly Cloudy"/>
</item>
</channel>
</rss>
Further Reading
If you enjoyed this post, then you may also be interested in:
No comments:
Post a Comment