Parsing XML
To verify the heuristics, we bring back the ubiquitous purchase order document, PO.xml, from the previous article, "XML in .NET: XPathNavigator and XSLT," as shown in Listing 1.
Listing 1: PO.xml Purchase Order
<?xml version="1.0" encoding="utf-8" ?> <po:PurchaseOrder xmlns:po="http://michalk.com/XmlDOM/PO.xsd"[ccc] xmlns:xsd="http://www.w3.org/2001/XMLSchema"[ccc] xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Number>1001</Number> <OrderDate>8/12/01</OrderDate> <BillToAddress> <Street>101 Main Street</Street> <City>Charlotte</City> <State>NC</State> <ZipCode>28273</ZipCode> </BillToAddress> <ShipToAddress> <Street>101 Main Street</Street> <City>Charlotte</City> <State>NC</State> <ZipCode>28273</ZipCode> </ShipToAddress> <LineItem Name="Computer Desk"[ccc] Description="Wood desk for computer" SKU="12345A123"[ccc] Price="499.99" Qty="1" /> <LineItem Name="Monitor"[ccc] Description="Computer Monitor 19-Inch" SKU="19A123"[ccc] Price="299.99" Qty="1" /> <LineItem Name="Computer" Description="Pentium 4 Computer"[ccc] SKU="411111" Price="999.99" Qty="1" /> <LineItem Name="Mouse" Description="Computer Mouse"[ccc] SKU="233B1" Price="49.99" Qty="1" /> </po:PurchaseOrder>
The code to navigate the XML document is featured in Listing 2. The first step is loading the DataSet with the XML document using the ReadXml method. Start navigation using the Tables collection to get the top-level PurchaseOrder DataTable and then enter a recursive function called ParseTables. ParseTables calls ParseRows to print out the columns that represent attributes. The output is shown in Listing 3; note the addition of the PurchaseOrder_ID field added to the purchase order and other subordinate tables. Movement from parent table to child tables happens through the use of the ChildRelations collection and the ChildTable property of the DataRelation object. An alternative method for navigating between rows of a parent table to corresponding rows in a child table is the GetChildRows method of the DataRow object.
Listing 2: DataSet XML Parsing and Navigation Demo Code
using System; using System.Data; namespace XmlDotNet { public class DataSetNavDemo { public static void Main() { DataSet ds = new DataSet(); // load the DataSet from the PO document ds.ReadXml("PO.xml"); // parse the DataSet starting at the // top-level PurchaseOrder table ParseTable(ds.Tables["PurchaseOrder"], 0); } public static void ParseTable(DataTable dt, int depth) { // call routine to print depth of current table // by spacing from the left margin PrintDepth(depth); Console.WriteLine(dt.TableName); // parse the rows/columns of the DataTable // which are mapped to XML attributes ParseRows(dt, depth+1); // use the child relationships of the current DataTable // mapped to an XML element to get at child DataTable's // mapped to child XML elements foreach (DataRelation dr in dt.ChildRelations) { ParseTable(dr.ChildTable, depth+1); } } public static void ParseRows(DataTable dt, int depth) { // parse through each DataColumn to get the XML // attribute that it is mapped for (int i =0; i < dt.Rows.Count; i++) { foreach (DataColumn dc in dt.Columns) { PrintDepth(depth+1); Console.Write(dc.ColumnName.ToString() + "="); Console.WriteLine(dt.Rows[i][dc.ColumnName].ToString() + " "); } Console.WriteLine(); } } public static void PrintDepth(int depth) { for (int i=0; i < depth; i++) Console.Write(" "); } } }
Listing 3: DataSet XML Parsing and Navigation Output
PurchaseOrder Number=1001 OrderDate=8/12/01 PurchaseOrder_Id=0 BillToAddress Street=101 Main Street City=Charlotte State=NC ZipCode=28273 PurchaseOrder_Id=0 ShipToAddress Street=101 Main Street City=Charlotte State=NC ZipCode=28273 PurchaseOrder_Id=0 LineItem Name=Computer Desk Description=Wood desk for computer SKU=12345A123 Price=499.99 Qty=1 PurchaseOrder_Id=0 Name=Monitor Description=Computer Monitor 19-Inch SKU=19A123 Price=299.99 Qty=1 PurchaseOrder_Id=0 Name=Computer Description=Pentium 4 Computer SKU=411111 Price=999.99 Qty=1 PurchaseOrder_Id=0 Name=Mouse Description=Computer Mouse SKU=233B1 Price=49.99 Qty=1 PurchaseOrder_Id=0