A Survey of APIs and Techniques for Processing XML
by Dare Obasanjo
|
Pages: 1, 2
Tree Model APIs
A tree-based API is an object model that represents an XML document as a tree of nodes. The object model consists of objects that map to various concepts from the XML 1.0 recommendation such as elements, attributes, processing instructions and comments. Such APIs provide mechanisms for loading, saving, accessing, querying, modifying, and deleting nodes from an XML document. The canonical example of a tree model API for processing XML is the W3C XML Document Object Model (DOM) which has inspired various programming language specific variations including JDOM and PyXML, for Java and Python respectively
Typically tree model APIs load the entire XML document into memory, and thus do not limit users to forward-only access of the XML data. This prevents traditional tree model APIs from being used in situations where large XML documents have to be processed. Although it is possible to build optimized tree model APIs that only load portions of an XML document as needed, such APIs are not in widespread usage.
The following code sample uses the Apache Xerces DOM
API to display the contents of the title and
author elements of books that have the
on-loan attribute set.
import org.apache.xerces.parsers.*;
import org.apache.xerces.dom.*;
import org.w3c.dom.*;
public class Test{
public static void main(String[] args) {
try {
DOMParser parser = new DOMParser();
parser.parse("books2.xml");
org.w3c.dom.Document doc = parser.getDocument();
NodeList list = doc.getElementsByTagName("book");
for(int i = 0, length = list.getLength(); i < length; i++){
Element book = (Element)list.item(i);
Attr borrower = book.getAttributeNode("on-loan");
if(borrower != null){
System.out.print(borrower.getValue() + " was loaned ");
//cast elements to Xerces specific classes
//to get access to getTextContent() method
ParentNode title = (ParentNode)
book.getElementsByTagName("title").item(0);
ParentNode author = (ParentNode)
book.getElementsByTagName("author").item(0);
System.out.println(title.getTextContent() + " by "
+ author.getTextContent());
}
}
}catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
The W3C DOM offers fairly limited functionality, primarily because it
was designed to be a generic API that could be implemented in a variety
of programming languages. This usually means that most people who utilize
the DOM API use helper methods, that is, extensions to the DOM API which
are specific to particular implementations (such as the call to
getTextContent() in the previous sample).
Cursor APIs
XML cursors are the newest class of APIs for processing XML. An XML cursor acts like a lens that focuses on one XML node at a time, but, unlike pull-based or push-based APIs, the cursor can be positioned anywhere along the XML document at any given time. In a way, pull model APIs are forward-only versions of a cursor model. Examples of XML cursor APIs are the .NET Framework's XPathNavigator class and the XmlCursor class from BEA's XMLBeans toolkit.
Just like tree model APIs, an XML cursor allows one to navigate, query, and manipulate an XML document loaded in memory. However, an XML cursor does not require the heavyweight interface of a traditional tree model API, where every significant token in the underlying XML must map to an object. This means that XML cursor APIs are potentially more memory efficient than tree model APIs.
More importantly, the fact that node objects do not need to be created for each information item in the underlying XML means that it makes it easier to create "XML views" of non-XML data. Whereas with traditional tree model APIs one had to duplicate an entire data source into a DOM or something similar to present the data source as XML, with XML cursors one can just implement a cursor over that data source that presents the underlying data as XML nodes when viewed through the cursor. This is the concept behind the ObjectXPathNavigator, which uses the .NET Framework's XPathNavigator, enabling one to treat an arbitrary set of objects as a virtual XML document that can be queried with XPath or transformed with XSLT.
The following code sample uses the .NET Framework's
XPathNavigator
class to display the contents of the title and
author elements of books that have the
on-loan attribute set.
using System;
using System.Xml.XPath;
public class Test{
public static void Main(string[] args){
XPathDocument doc = new XPathDocument("books2.xml");
XPathNavigator nav = doc.CreateNavigator();
//select every book with an on-loan attribute
XPathNodeIterator iterator =
nav.Select("/books/book[@on-loan]");
while (iterator.MoveNext()){
//create a navigator pointing at same position
XPathNavigator nav2 = iterator.Current.Clone();
string borrower = nav2.GetAttribute("on-loan", "");
nav2.MoveToFirstChild();
string title = nav2.Value;
nav2.MoveToNext();
string author = nav2.Value;
Console.WriteLine("{0} was loaned {1} by {2}",
borrower, title, author);
}
}
}
Object to XML Mapping APIs
It is often convenient to map the contents of an XML document to objects that better represent the data within the XML document than interacting with the data via an XML-based object model. Developers working in object oriented languages typically prefer working with information as objects and classes as opposed to attempting to extract information from untyped XML nodes.
There are numerous advantages to this approach. First, the memory
footprint of XML data can be reduced because information isn't being
stored as nodes and textual data but as classes and programming
language primitives. A DOM node that represents a
<foo> element that contains a numeric value as text
is more memory intensive than its counterpart foo class
with an integer field. In particular, the memory footprint is better if
you are able to turn lots of leaf values into primitive valued fields,
or if you can do away with parent and sibling pointers. Second, it is
more convenient to perform calculations on certain types of data such
as numbers or dates as native programing language constructs than it is
to interact with them as string values stored in nodes. But, third, the
most compelling argument is the improved ease of use. It's no longer
nessary to navigate the XML tree to access the information but instead
one can simply access data as fields and properties of an object.
Object to XML mapping technologies have certain limitations that
prevent them from replacing traditional methods for accessing XML
data. Most of these technologies cannot represent all the information
in an XML document with full fidelity. Many do not preserve processing
instructions and comments. Similarly mixed content is
problematic to map to objects since the tendency is to map element and
attribute nodes to objects and text nodes to the values of fields or
properties in said objects. Although the order of elements is
significant in an XML document, this typically cannot be enforced on
objects. Most object oriented languages do not have a way of expressing
that in a book class the title field precedes the
author field, although one could use ordered collections to get
around this problem.
In most cases an XML document's schema (which could be a DTD, W3C XML Schema document, or proprietary schema language) is used as a basis for mapping the XML to native objects in the target programming language. Examples of such Object<->XML mapping technologies include JAXB, the .NET Framework's XmlSerializer and Castor. Another limitation of Object<->XML mapping technologies is that there are often impedance mismatches between XML schema languages such as W3C XML Schema and object oriented concepts.
The following sample shows how to utilize the .NET Framework's
XmlSerializer
class to display the contents of the title and
author elements of books that have the
on-loan attribute set.
- Obtain the schema for your XML document. Below is a schema for my XML file generated using the
Microsoft XSD Inference tool.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified"> <xs:element name="books"> <xs:complexType> <xs:sequence> <xs:element name="book" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="title" type="xs:string" /> <xs:element name="author" type="xs:string" /> </xs:sequence> <xs:attribute name="publisher" type="xs:string" use="required" /> <xs:attribute name="on-loan" type="xs:string" use="optional" /> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> - Generate a C# class from the XML schema using
xsd.exe
using System.Xml.Serialization; /// <remarks/> [System.Xml.Serialization.XmlRootAttribute("books", Namespace="", IsNullable=false)] public class books { /// <remarks/> [System.Xml.Serialization.XmlElementAttribute("book")] public booksBook[] book; } /// <remarks/> public class booksBook { /// <remarks/> public string title; /// <remarks/> public string author; /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute (Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] public string publisher; /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute("on-loan", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] public string onloan; } - Write code
using System; using System.Xml.Serialization; using System.IO; public class Test{ public static void Main(string[] args){ TextReader reader = new StreamReader("books2.xml"); XmlSerializer serializer = new XmlSerializer(typeof(books)); books myBooks = (books)serializer.Deserialize(reader); reader.Close(); foreach(booksBook book in myBooks.book){ if(book.onloan != null){ Console.WriteLine("{0} was loaned {1} by {2}", book.onloan, book.title, book.author); } } } }
XML Specific Languages
It seems natural that one would process XML using a language that is designed for processing XML as opposed to going through traditional programming languages. For performing complex operations on XML data, all of the aforementioned techniques suffer from either being too cumbersome, require too many lines of code, or do not handle all of XML. In such cases, the wise decision is to go with a language which natively understands how to process XML to do the heavy lifting and invoke that from the target programming language. Examples of languages specifically designed for processing and manipulating XML include XPath, XQuery, XSLT, and Xtatic.
The following sample is an XQuery expression that displays the contents
of the title and author elements of books
that have the on-loan attribute set.
for $b in document("books2.xml")/books/book[@on-loan]
return (string($b/@on-loan), " was loaned ",
$b/title/text(), " by ", $b/author/text())
There are various sites where one can try out sample XQuery expressions, including QEXO XQuery Sandbox and Microsoft's XQuery demo site
Conclusion
This article shows that processing XML isn't simply a choice of in-memory (DOM) versus streaming (SAX). Rather, it's a tradeoff between a number of choices with lots of small nuances. The following table is s supplement to this article: it provides a quick overview of the distinguishing characteristics of the various approaches and techniques
| Push Model | Pull Model | Tree Model | Cursor Model | Object to XML Mapping | XML-Specific Languages | |
|---|---|---|---|---|---|---|
| Forward-Only Access (streaming) | X | X | ||||
| Random Access (in memory) | X | X | X | X | ||
| Schema Required | X | |||||
| Read-only access | X | X | depends | |||
| Event based | X | |||||
| Emphasizes XML data model | X | X | X | X | X |
- String based API
2003-08-06 05:38:05 Julian Turner - Similiar article from Elliotte Rusty Harold?
2003-07-17 16:43:39 Wai Yip Tung - Xineo OAX is another free software alternative
2003-07-17 01:29:09 Frédérik Bilhaut - The link !
2003-07-17 01:29:56 Frédérik Bilhaut - Don't forget STX
2003-07-16 05:56:54 Oliver Becker - Well-done article
2003-07-11 03:01:48 Reinout van Rees