Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
XML and WebObjects KeyValueCoding
[go: Go Back, main page]

XML and WebObjects KeyValueCoding


The following is an article I wrote over a year ago, I recently used the XMLKeyVaLueCoding technique for a client and it worked out just fine. I have also used the WOXMLCoding technique in the past as well, take your pick.

The techniques described in the article are demonstrated in the following to example WebObjects applications:

xmlkeyvaluecoding.tgz woxmlcodingwithmodel.tgz

Introduction

As the web evolves XML representations of data have become more and more common. If you have not done so already, you may soon find yourself integrating XML data into your WebObjects application.

This article offers several choices for incorporating XML data into WebObjects applications. The sample XML data is the Slashdot XML news feed at http://slashdot.org/slashdot.xml.

The source code listings are taken from examples available on this site (WOXMLCodingWithModel and XMLKeyValueCoding).

WOXMLCoding

WebObjects ships with its own XML serialization API. The Foundation classes can be serialized with this API and any custom class which implements the WOXMLCoding interface can also be serialized. The default XML file format maintains circular references and Java class names. A model file can be provided which the API uses to map XML tags and attributes to Java classes and properties. The javadoc describes the API and the model file format.

A simple model for the slashdot.xml file would look like this:

<model> <entity name="com.mjh.examples.woxmlcoding.Slashdot" xmlTag="backslash" ignoreUnmappedTags="YES"> <property name="stories" xmlTag="story" forceList="YES" /> </entity> <entity name="com.mjh.examples.woxmlcoding.Story" xmlTag="story"> <property name="title" xmlTag="title" /> <property name="url" xmlTag="url" /> <property name="time" xmlTag="time" /> <property name="author" xmlTag="author" /> <property name="department" xmlTag="department" /> <property name="topic" xmlTag="topic" /> <property name="comments" xmlTag="comments" /> <property name="section" xmlTag="section" /> <property name="image" xmlTag="image" /> </entity> </model>

Once the model is constructed the XML file can be converted to Java Objects with a few lines of code:

WOResourceManager rm = resourceManager(); String modelFile = rm.pathForResourceNamed(SLASHDOT_MAPPING_MODEL_FILE, null, null); WOXMLDecoder decoder = WOXMLDecoder.decoderWithMapping(modelFile); java.net.URL url = new java.net.URL("http://slashdot.org/slashdot.xml"); InputStream inputStream = url.openStream(); InputSource inputSource = new InputSource(inputStream); Object obj = decoder.decodeRootObject(inputSource); slashdot = (Slashdot)obj; NSArray stories = slashdot.getStories();

Now that the XML data has been converted to Java objects the properties can be used in WOComponent bindings like any other. This type of approach is adopted by other frameworks, such as Castor and the Apache Digester NSKeyValueCoding

WebObjects uses the NSKeyValueCoding interface to simplify access to properties across nested relationships using a "keypath", a dot separated path which is traversed to obtain a required reference without the developer having to write code to invoke methods on the objects on the path.

There is an obvious similarity between the nested structure of a set of XML tags and the nested references of Java objects. What if it was possible to treat an XML document (more correctly the parsed DOM tree) as a set of nested Java references using NSKeyValueCoding? A simple wrapper class - XMLKeyValueCoding can do the job.

To obtain a reference to the XMLDocument with NSKeyValueCoding:

slashdot = new XMLKeyValueCoding("http://slashdot.org/slashdot.xml");

Now you can use the 'slashdot' reference in component bindings as you would any other object:

Stories: WORepetition { list = application.slashdot.story; item = story; } Link: WOHyperlink { href=story.url; target="slashdot"; } Title: WOString { value = story.title; }

XMLKeyValueCoding adapts the DOM traversal API to NSKeyValueCoding:

public Object valueForKey(String key) { Object result = null; if (element.hasAttribute(key)) { result = element.getAttribute(key); } else { ArrayList list = getChildrenForKey(key); if (list.size() == 1) { result = list.get(0); } else { result = converListToArray(list); } } return result; }

Similar techniques are applied in other frameworks such as Velocity to incorporate XML data into web pages with minimal effort for the coder.

XML/XSLT

XSLT is the W3C technology for applying transformations to XML documents. A recent Stepwise article Web Publishing with WebObjects 5 and XSLT covers this technique in detail.

One caveat with integrating XSLT generated HTML into your website is the problem of handling URL's in the XSLT generated content. If you need to generate a hyperlink back into your app, then your XSLT stylesheet will have to be smart enough to generate WO style URLs.

Conclusions
  • If you need to convert XML documents into objects with business logic or convert your business objects to XML for integration with other systems, then WOXMLCoding with a model is ideal.
  • If you just wish to display elements of the XML data in your WebObjects components the the NSKeyValueCoding approach works great, there is no model to write, no Java classes to code and compile.
  • If you have complex conversion needs or must apply formatting to the data elements, then XSLT covers almost every base.