- The Common Node
- Navigating the DOM
- Key Extended Nodes
- Building the DOM
- Conclusion
Navigating the DOM
The XmlNode class also provides a standard navigational interface for traversing nodes in a document. Part of the navigation interface listed next is from the DOM specifications; SelectSingleNode and SelectNodes methods are Microsoft extensions that take an XPath statement and return the appropriate node(s).
ChildNodes
HasChildNodes
Attributes
FirstChild
LastChild
NextSibling
PreviousSibling
ParentNode
OwnerDocument
SelectSingleNode
SelectNodes
To help with navigation among a group of nodes, the DOM specifies two standard node collections: the XmlNodeList for ordered access by position, and the XmlNamedNodeMap for access by position or by name. Nodes use XmlNodeList for collections of child nodes thru the ChildNodes property. Nodes use the XmlAttributesCollection class, which derives from XmlNamedNodeMap, to represent attributes through the Attributes property. The .NET framework makes life easier by providing indexer access to the contents of each type of collection.
The following list shows the XmlNodeList navigation methods:
Item
Count
Here are the XmlNamedNodeMap navigation methods:
GetNamedItem
Item
Count
Listing 1 shows how to access a child element and a child attribute through the indexer.
Listing 1: Using Indexers Instead of Methods to Access Collection Data
XmlNodeList nodes = GetNodeListFromSomewhere(); Console.WriteLine("Name: {0}",nodes[5].Name); Console.WriteLine("Attribute ID:{0}", nodes[5].Attributes["ID"].Value);
Now that you have reviewed the basic node navigation and value-retrieval methods of an XmlDocument, you can pull the pieces together and parse a document for structure and information. Listing 3 is an example that loads and navigates through a typical purchase order document. The full text of the PO.xml file is visible in Listing 2. In the main method the XmlDocument node loads PO.xml from the file and calls the WalkNode method with the document element. The code in the WalkNode functions recursively calls itself for the child element nodes and attribute node to walk through each level of the DOM tree to produce the output in Listing 4.
Listing 2: PO.xml
<?xml version="1.0" encoding="utf-8" ?> <po:PurchaseOrder xmlns:po="http://michalk.com/XmlDOM/PO.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 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" Description="Wood desk for computer" SKU="12345A123" Price="499.99" Qty="1" /> </po:PurchaseOrder>
Listing 3: PO Navigation Code
using System; using System.Xml; namespace XmlDOM { class DOMNavTutorial { static void Main(string[] args) { // load the PO document XmlDocument dom = new XmlDocument(); dom.Load("C:\\PO.xml"); // walk node using common XmlNode interface Console.WriteLine("Walking nodes in document..\n"); WalkNode(dom.DocumentElement, 0); // navigate to adjacent nodes from BillToAddress XmlNode shiptonode = dom.SelectSingleNode("//BillToAddress"); NavigateAdjacentNodes(shiptonode); } static void WalkNode(XmlNode node, int depth) { // print out info about the current node for (int i=0; i < depth; i++) Console.Write(" "); Console.WriteLine("Type:{0} Name:{1} Value:{2}", node.NodeType, node.Name, node.Value); // parse all child attribute nodes XmlAttributeCollection attrs = node.Attributes; if (attrs != null) { foreach (XmlNode childNode in attrs) { WalkNode(childNode, depth+1); } } // parse all child element nodes XmlNodeList elems = node.ChildNodes; foreach (XmlNode childNode in elems) { WalkNode(childNode, depth+1); } } static void NavigateAdjacentNodes(XmlNode node) { Console.WriteLine("\nNavigate from node:{0}\n",node.Name); Console.WriteLine("First Child: {0}", node.FirstChild.Name); Console.WriteLine("Last Child: {0}", node.LastChild.Name); Console.WriteLine("Parent Node: {0}", node.ParentNode.Name); Console.WriteLine("Previous Sibling: {0}", node.PreviousSibling.Name); Console.WriteLine("Next Sibling: {0}", node.NextSibling.Name); Console.WriteLine("Owner Document: {0}", node.OwnerDocument.Name); } } }
Listing 4: Navigating the PO
Walking nodes in document.. Type:Element Name:po:PurchaseOrder Value: Type:Attribute Name:xmlns:po Value:http://michalk.com/XmlDOM/PO.xsd Type:Text Name:#text Value:http://michalk.com/XmlDOM/PO.xsd Type:Attribute Name:xmlns:xsd Value:http://www.w3.org/2001/XMLSchema Type:Text Name:#text Value:http://www.w3.org/2001/XMLSchema Type:Attribute Name:xmlns:xsi Value:http://www.w3.org/2001/XMLSchema-
instance Type:Text Name:#text Value:http://www.w3.org/2001/XMLSchema- instance Type:Element Name:Number Value: Type:Text Name:#text Value:1001 Type:Element Name:OrderDate Value: Type:Text Name:#text Value:8/12/01 Type:Element Name:BillToAddress Value: Type:Element Name:Street Value: Type:Text Name:#text Value:101 Main Street Type:Element Name:City Value: Type:Text Name:#text Value:Charlotte Type:Element Name:State Value: Type:Text Name:#text Value:NC Type:Element Name:ZipCode Value: Type:Text Name:#text Value:28273 Type:Element Name:ShipToAddress Value: Type:Element Name:Street Value: Type:Text Name:#text Value:101 Main Street Type:Element Name:City Value: Type:Text Name:#text Value:Charlotte Type:Element Name:State Value: Type:Text Name:#text Value:NC Type:Element Name:ZipCode Value: Type:Text Name:#text Value:28273 Type:Element Name:LineItem Value: Type:Attribute Name:Name Value:Computer Desk Type:Text Name:#text Value:Computer Desk Type:Attribute Name:Description Value:Wood desk for computer Type:Text Name:#text Value:Wood desk for computer Type:Attribute Name:SKU Value:12345A123 Type:Text Name:#text Value:12345A123 Type:Attribute Name:Price Value:499.99 Type:Text Name:#text Value:499.99 Type:Attribute Name:Qty Value:1 Type:Text Name:#text Value:1
After the xml document traversal is complete, you traverse from the ShipToAddress element to show off the full range of XmlNode navigational methods in the NavigateAdjacentNodes method. The ShipToAddress node is located in the document using the SelectSingleNode method and an XPath expression. Listing 5 is the resulting output.
Listing 5: Result of Node Traversal Around BillToAddress
Navigate from node:BillToAddress First Child: Street Last Child: ZipCode Parent Node: po:PurchaseOrder Previous Sibling: OrderDate Next Sibling: ShipToAddress Owner Document: #document