Working XML Data


Extensible Markup Language, better known as XML, has been a significant development over the last few years , so much so that XML is a key component of perhaps all major applications and products conceptualized and developed today. The main use of XML is as a portable mechanism for representing self-describing data. For instance, if you share order information with another application or another partner, you could use XML as a representation for the order information.

 
 <?xml version="1.0"?> <Order>    <OrderHeader>       <OrderId>100</OrderId>       <OrderDate>08/31/2003</OrderDate>    </OrderHeader>    <OrderDetails>       <OrderLine>          <Item>XYZ Computer</Item>          <Price>3000</Price>       </OrderLine>       <OrderLine>          <Item>xyz RAM</Item>          <Price>50</Price>       </OrderLine>    </OrderDetails> </Order> 

As shown by the preceding XML document, an XML document contains both the data as well as a set of surrounding tags that represent the metadata for the data items contained in it. This capability is what makes XML so unique and portable. For instance, this document can be parsed and processed by any platform written in any language running in any operating system by any company. Consider an alternative representation written in a CSV format:

 
 ORDER_HEADER,100,08/31/2003 ORDER_LINE,1,XYZ Computer,3000 ORDER_LINE,1,xyz RAM, 50 

Even a simplified order representation such as this would require an extensive knowledge exchange between the two parties on how to process the enclosed data. You can well imagine the complexity that could be introduced with a representation of an actual order.

The .NET FCL System.Xml namespace provides a set of classes and interfaces for easy creation, processing, and transformation of XML documents. In fact, the .NET XML Web services capability heavily utilizes XML to deliver, distribute, and interoperate with applications. Key classes in the System.Xml namespace are the following:

  • XmlDocument ” Represents an in-memory representation of an XML document

  • XmlElement, XmlAttribute ” Represents an XML element, attribute

  • XmlNode ” Represents a node of an XML document

  • XmlTextReader ” An efficient, performance-centric, forward-only implementation of a reader for XML documents

  • XmlTextWriter ” An efficient, performance-centric, forward-only implementation of a writer for XML documents

  • XmlValidatingReader ” Validates XML documents with an associated XML Schema document

  • XmlConvert ” Provides encoding/decoding between CLR types and XML Schema “based documents

  • XmlDataDocument ” Allows processing of relational data through the XML

Creating XML Documents

Although you can directly create XML documents using the XmlDocument class, XmlTextWriter provides an easy-to-use and efficient way for creating XML documents. However, XmlTextWriter provides only forward-only noncached implementation. So if you require insertion of XML elements and attributes at arbitrary positions in the XML document, you should use the XmlDocument class instead.

For example, Listing 4.21 creates and prints out the Order.xml document illustrated earlier:

Listing 4.21 Creating XML Documents
 using System; using System.Xml; using System.IO; class CreateXml {    public static void Main()    {       StringWriter sw = new StringWriter();       XmlTextWriter xtw = new XmlTextWriter(sw);       xtw.Formatting  = Formatting.Indented;       xtw.WriteStartDocument(true);       xtw.WriteStartElement("Order");        xtw.WriteStartElement("OrderHeader");          xtw.WriteElementString("OrderId","100");          xtw.WriteElementString("OrderDate","08/31/2003");        xtw.WriteEndElement();        xtw.WriteStartElement("OrderDetails");         xtw.WriteStartElement("OrderLine");          xtw.WriteElementString("Item","XYZ Computer");          xtw.WriteElementString("Price","3000");        xtw.WriteEndElement();         xtw.WriteStartElement("OrderLine");          xtw.WriteElementString("Item","xyz RAM");          xtw.WriteElementString("Price","50");         xtw.WriteEndElement();         xtw.WriteEndElement();       xtw.WriteEndElement();       Console.WriteLine(sw.ToString());    } } 

Processing XML Documents

The processing of an XML document is where the main work related to XML comes in. Depending on what you are trying to do, there are a couple of alternatives. The XmlTextReader provides fast, forward-only, noncached access to XML data. The XmlDocument itself represents an in-memory tree representation of the XML document.

For instance, you can create a simple application (as shown in Listing 4.22) that will parse the Order.xml document and calculate the Order value, which in this scenario translates to summing up the various price elements.

Listing 4.22 Parsing XML Documents
 using System; using System.IO; using System.Xml; using System.Collections; class ParseXml {    public static void Main()    {       XmlTextReader reader = new XmlTextReader("Order.xml");       XmlDocument xml = new XmlDocument();       xml.Load(reader);       IEnumerator e = xml.DocumentElement.GetEnumerator();       XmlNode node;       while (e.MoveNext())       {          node = (XmlNode) e.Current;          if (node.Name.Equals("OrderDetails"))          {             IEnumerator lines = node.GetEnumerator();             int amount=0;             while (lines.MoveNext())             {                XmlNode line = (XmlNode) lines.Current;                IEnumerator lineEnum = line.GetEnumerator();                int price = 0;                while (lineEnum.MoveNext())                {                   XmlNode lineNode = (XmlNode) lineEnum.Current;                   if (lineNode.Name.Equals("Price"))                   {                      price = Int32.Parse(lineNode.FirstChild.Value);                   }                }                amount = amount+(price);             }             Console.WriteLine("Order Amount:{0}",amount);          }       }    } } 

Running the ParseXml application should yield the following output:

 
 Order Amount:3050 

Using XPath

The System.Xml.XPath namespace provides a set of classes and interfaces that implement an XPath engine, which is compliant with the W3C XPath 1.0 Specification. Key classes in the namespace are XPathDocument, XPathExpression, XPathNavigator, and XPathNodeIterator. For instance, for the Order.xml document, you can easily create a single XPath expression, "sum(//Price)" , which will provide the order amount.

WHAT IS XPATH?

XPath provides a very convenient mechanism for addressing elements of the XML document tree, typically useful for selecting a small subset of the data from the XML document.


For instance, Listing 4.23 shows XPath being used to get the identical output for calculating the order amount:

Listing 4.23 Using XPath Expressions
 using System; using System.IO; using System.Xml; using System.Xml.XPath; class UseXPath {    public static void Main()    {       XPathDocument doc = new XPathDocument("Order.xml");       XPathNavigator xNav = doc.CreateNavigator();       XPathExpression sumExpr =xNav.Compile("sum(//Price/text())");       Console.WriteLine("Order Amount:{0}",xNav.Evaluate(sumExpr));    } } 

Transforming XML Documents

In various scenarios, XML documents must be transformed into other XML, HTML, or text documents. Although this can be achieved through straightforward XML parsing and/or XPath, W3C has defined a standard for styling and transforming XML documents, XSLT (XML Transformations).

IS XSLT FOR XML TO HTML TRANSFORMATIONS ONLY?

XSLT can be used not only for transforming XML documents into HTML, but to any other XML documents as well. For instance, you can use XSLT to convert an order document in a standard XML-based vocabulary into your own XML vocabulary. In addition, XSLT can be used to create non-XML content such as CSVs (comma separated values). In fact, I have seen practical applications where XSLT has been used to create source code from an XML-tagged metadata structure.


XSLT internally uses XPath to address elements of the XML document and provides template-based programming language constructs (written in XML) to match components of the XML document. For instance, Listing 4.24 is the XSLT document that could be used to transform the Order.xml document into HTML so that it can be displayed on a Web page or sent as an email attachment.

Listing 4.24 XSLT for Creating HTML View from an XML Order
 <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">    <xsl:template match="Order">       <html>          <h1>Order Information - <xsl:value-of select="OrderHeader/OrderId"/></h1>          <h3>Order Header</h3>          <b>Order ID:</b><xsl:value-of select="OrderHeader/OrderId"/><br/>          <b>Order Date:</b><xsl:value-of select="OrderHeader/OrderDate"/><br/>          <h3>Order Details</h3>          <table border="1">             <tr>                <td><b>Item</b></td>                <td><b>Price</b></td>             </tr>             <xsl:for-each select="OrderDetails/OrderLine">              <tr>                <td><xsl:value-of select="Item"/></td>                <td><xsl:value-of select="Price"/></td>              </tr>             </xsl:for-each>          </table>       </html>    </xsl:template> </xsl:transform> 

To enable XSLT processing, the .NET FCL provides the implementation of the XSLT standard in the System.Xml.Xsl namespace; the major class in that package is XslTransform, which allows arbitrary XML documents (or even a dynamically created XML document tree) to be processed with an XSLT document as shown in Listing 4.25.

Listing 4.25 Applying XSLT Transformations
 using System; using System.IO; using System.Xml; using System.Xml.Xsl; class XmlXsl {    public static void Main()    {       XslTransform xslt = new XslTransform();       xslt.Load("Order.xsl");       XmlTextReader reader = new XmlTextReader("Order.xml");       XmlDocument xml = new XmlDocument();       xml.Load(reader);       StringWriter html = new StringWriter();       xslt.Transform(xml,null,html,null);       Console.WriteLine(html);    } } 

The HTML output generated by the processor is shown next . If you open a Web browser, you should be able to see the Order document rendered similar to Figure 4.1.

 
 <html>   <h1>Order Information - 100</h1>   <h3>Order Header</h3>   <b>Order ID:</b>100<br>   <b>Order Date:</b>08/31/2003<br>   <h3>Order Details</h3>   <table border="1">         <tr>               <td><b>Item</b></td>               <td><b>Price</b></td>         </tr>         <tr>               <td>XYZ Computer</td>               <td>3000</td>         </tr>         <tr>               <td>xyz RAM</td>               <td>50</td>         </tr>    </table> </html> 
Figure 4.1. Order information in HTML, converted using XML/XSL.

Binding XML Schemas to .NET Classes

Typical programming tasks in applications that involve XML parsing and querying include assigning the values of an object to values read from an XML file and storing the values represented by an object, including all its fields, into an XML file. Although the parsing mechanisms described in the previous sections can be used to accomplish that, it involves a good amount of work and is error prone. The .NET Framework provides a utility called the XML Schemas/DataTypes support utility (or xsd.exe) that allows XML Schemas to be bound to CLR types and vice versa. XML Schema is an XML document based on the W3C XML Schema Specification and provides structural and data-type information for a group of XML documents.

As an example of an XML Schema document, you can create an XML Schema for the Order.xml document that you have used in the examples so far (Listing 4.26).

Listing 4.26 XML Schema for Order
 <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Order">  <xs:complexType>    <xs:sequence>     <xs:element ref="OrderHeader"/>     <xs:element ref="OrderDetails"/>    </xs:sequence>  </xs:complexType> </xs:element> <xs:element name="OrderHeader">  <xs:complexType>    <xs:sequence>     <xs:element ref="OrderId"/>     <xs:element ref="OrderDate"/>    </xs:sequence>  </xs:complexType> </xs:element> <xs:element name="OrderId" type="xs:string"/> <xs:element name="OrderDate" type="xs:string"/> <xs:element name="OrderDetails">  <xs:complexType>   <xs:sequence>    <xs:element ref="OrderLine" minOccurs="0" maxOccurs="unbounded"/>   </xs:sequence>  </xs:complexType> </xs:element> <xs:element name="OrderLine">  <xs:complexType>   <xs:sequence>    <xs:element ref="Item"/>    <xs:element ref="Price"/>   </xs:sequence>  </xs:complexType> </xs:element> <xs:element name="Item" type="xs:string"/> <xs:element name="Price" type="xs:string"/> </xs:schema> 

To create a mapped CLR type for the XML Schema, use the xsd utility to generate a set of classes for the XML Schema.

 
 xsd Order.xsd /classes 

This utility generates a file, Order.cs (shown next), which contains the data type definitions of the Order XML Schema document. (Note: Comments from the autogenerated file have been removed for brevity.)

 
 using System.Xml.Serialization; [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] public class Order {     public OrderHeader OrderHeader;     [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)]     public OrderLine[] OrderDetails; } [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] public class OrderHeader {     public string OrderId;     public string OrderDate; } [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] public class OrderLine {     public string Item;     public string Price; } [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] public class OrderDetails {     [System.Xml.Serialization.XmlElementAttribute("OrderLine")]     public OrderLine[] OrderLine; } 

To use the generated Order class, the XmlSerializer class found in the System.Xml. Serialization namespace can be used to deserialize (parse XML) or serialize (generate XML). For instance, Listing 4.27 shows a simple application that reads an XML document, binds it to the Order object, and then uses the assigned fields in the Order object.

Listing 4.27 Deserializing XML Documents
 using System; using System.IO; using System.Xml; using System.Xml.Serialization; class BindXml {    public static void Main()    {       try {       XmlSerializer xs = new XmlSerializer(typeof(Order));       Stream fs = new FileStream("Order.xml", FileMode.Open);             XmlReader reader = new XmlTextReader(fs);       Order o = (Order) xs.Deserialize(reader);       Console.WriteLine("Order #{0} created on {1}, for {2} Items",          o.OrderHeader.OrderId,o.OrderHeader.OrderDate,o.OrderDetails.Length);       } catch (Exception ex) {       Console.WriteLine(ex.Message);       }    } } 

Running the preceding program should yield the following output:

 
 Order #100 created on 08/31/2003, for 2 Items 


Microsoft.Net Kick Start
Microsoft .NET Kick Start
ISBN: 0672325748
EAN: 2147483647
Year: 2003
Pages: 195
Authors: Hitesh Seth

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net