DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • SmartXML: An Alternative to XPath for Complex XML Files
  • Validate XML Request Against XML Schema in Mule 4
  • Migrate Serialized Java Objects with XStream and XMT
  • What Is Ant, Really?

Trending

  • Efficient API Communication With Spring WebClient
  • Introducing Graph Concepts in Java With Eclipse JNoSQL
  • SaaS in an Enterprise - An Implementation Roadmap
  • Go 1.24+ Native FIPS Support for Easier Compliance
  1. DZone
  2. Coding
  3. Languages
  4. Mapping Objects to Multiple XML Schemas - Weather Example

Mapping Objects to Multiple XML Schemas - Weather Example

By 
Blaise Doughan user avatar
Blaise Doughan
·
Dec. 28, 11 · Interview
Likes (0)
Comment
Save
Tweet
Share
8.7K Views

Join the DZone community and get the full member experience.

Join For Free

I have written previous posts on EclipseLink JAXB (MOXy)'s @XmlPath and external binding file extensions.  In this post I will demonstrate how powerful these extensions are by mapping a single object model to two different XML schemas.  To make the example more "real", the XML data will come from two different services that provide weather information:  Google and Yahoo.

Java Model

The following domain model will be used for this post:

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:

http://www.google.com/ig/api?weather=Ottawa

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.JAXBContextFactory

For 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

Below is the result of running the demo code.  The output represents the portion of the XML document that we had mapped to:

expand source

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):

http://weather.yahooapis.com/forecastrss?w=3369

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"/>
 
<b>Current Conditions:</b>
 
Mostly Cloudy, 66 F
 
 
<b>Forecast:</b>
 
Thu - Partly Cloudy. High: 75 Low: 57
 
Fri - Partly Cloudy. High: 79 Low: 53
 
 
 
<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>
 
 
(provided by <a href="http://www.weather.com" >The Weather Channel</a>)
 
]]></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

Since we can not supply a second set of mappings to an object model via annotations, we must supply subsequent mappings by leveraging MOXy's XML metadata.  By default MOXy's mapping document is used to supplement any annotations that are specified on the model.  However, if the xml-mapping-metadata-complete flag is set, then the XML metadata will completely replace the metadata provided by annotations (the annotations for the Google mapping will remain on the POJOs, but the xml-mapping-metadata-complete flag tells MOXy to ignore them).


<?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>

 

From http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html

XML Object (computer science) Schema

Opinions expressed by DZone contributors are their own.

Related

  • SmartXML: An Alternative to XPath for Complex XML Files
  • Validate XML Request Against XML Schema in Mule 4
  • Migrate Serialized Java Objects with XStream and XMT
  • What Is Ant, Really?

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!