- XML Reader Navigation
- Reading Attributes
- Movement and Advanced Reads
- Creation Using XMLWriter
- Validating Your Work
- Summary
Movement and Advanced Reads
The XmlReader API provides other advanced movement techniques that make life simpler for you and allow you to skip processing of portions of the document. This is a big win over the SAX model, which requires you to process each element. If you have left in whitespace and you want to skip certain parts of the document, you can use the MoveToContent method. It seeks nonwhitespace text, CDATA, and Element, EndElement, EntityReference, or EndEntity nodes. If the current node is not of that type, it moves the cursor until it finds one. Be careful to move the node off a content node before you call this method, or nothing happens. If you want to skip a single node, you can call the Skip method. The following shows the full list of movement functions:
- Skip
- MoveToContent
- MoveToAttribute
- MoveToElement
- MoveToFirstAttribute
- MoveToNextAttribute
There are also Read methods that allow more granularity and type safety when reading the document. If they are positioned on an attribute node, you can retrieve the text value of the attribute using the ReadAttributeValue call. If they are positioned on an element with text content, you can read each portion of the element with granular calls: ReadStartElement, ReadString, and ReadElement. If you are interested in just reading the text part of an element node, you can call the handy ReadElementString method. ReadInnerXml and ReadOuterXml are useful when you want to retrieve the serialized textual form of the nodes without having to parse down into them. The various Read methods are enumerated here:
- Read
- ReadAttributeValue
- ReadElementStrint
- ReadStartElement
- ReadEndElement
- ReadString
- ReadChars
- ReadInnerXML
- ReadOuterXML
Listing 7 is a demonstration of the different ways of moving and reading the purchase order XML document. The overall loop is dependent on the EOF condition, and the cursor is moved by the combination of a MoveToContent and consumption of the content nodes that it moves to. The main logic of the code uses a chained if/then statement to check for the element nodes that you are interested in processing. The code that works on the City element shows how to process an element node with textual content by reading in the start element node, text node, and end element node. The State element-handling code shows how easy it is to retrieve the text node value with minimal work. The code associated with the LineItem element shows how to retrieve attribute values using GetAttribute and the name of the attribute. If you reach the bottom of the if/then statement, you must execute a Read to move the cursor beyond the current content node and prevent MoveToContent from going into an infinite loop. Output is shown in Listing 8.
Listing 7: XmlTextReader Advanced Read and Movement Demo Code
using System; using System.Xml; namespace XmlDemo { public class ReaderNavMove { public static void Main() { // load the PO document XmlTextReader reader = new XmlTextReader("PO.xml"); // leave in whitespace Console.WriteLine("Walking nodes in document..\n"); // use EOF property as loop breaking mechanism while (!(reader.EOF)) { // move the node to a content node if the // current node is not one of the following: //non-whitespace text //CDATA //Element //EndElement //EntityReference //EndEntity reader.MoveToContent(); Console.WriteLine("Node Type:{0} Name: {0}", reader.NodeType, reader.Name); // check for the start of the State element if (reader.IsStartElement() && reader.Name.Equals("City")) { // read <City> reader.ReadStartElement(); // read city name string Console.WriteLine(" -----> City: {0}", reader.ReadString()); // read </City> reader.ReadEndElement(); } // check for the start of the City element else if (reader.IsStartElement() && reader.Name.Equals("State")) { // read the state name string // part between <State> ... </State> // ...this is much easier than the city handling Console.WriteLine(" -----> State: {0}", reader.ReadElementString()); } // check for the start of the LineItem element else if (reader.IsStartElement() && reader.Name.Equals("LineItem")) { // read the Name attribute value Console.WriteLine(" -----> LineItem Name: {0}", reader.GetAttribute("Name")); // read the Price attribute value Console.WriteLine(" -----> LineItem Price: {0}", reader.GetAttribute("Price")); // move beyond the current element node reader.Read(); } else // move to the next node // (this is required because the MoveToContent // will not move the cursor if we are currently // positioned on a node with content) reader.Read(); } } } }
Listing 8: XmlTextReader Advanced Read and Movement Demo Output
Node Type:Element Name: Element Node Type:Element Name: Element Node Type:Text Name: Text Node Type:EndElement Name: EndElement Node Type:Element Name: Element Node Type:Text Name: Text Node Type:EndElement Name: EndElement Node Type:Element Name: Element Node Type:Element Name: Element Node Type:Text Name: Text Node Type:EndElement Name: EndElement Node Type:Element Name: Element -----> City: Charlotte Node Type:Element Name: Element -----> State: NC Node Type:Element Name: Element Node Type:Text Name: Text Node Type:EndElement Name: EndElement Node Type:EndElement Name: EndElement Node Type:Element Name: Element Node Type:Element Name: Element Node Type:Text Name: Text Node Type:EndElement Name: EndElement Node Type:Element Name: Element -----> City: Charlotte Node Type:Element Name: Element -----> State: NC Node Type:Element Name: Element Node Type:Text Name: Text Node Type:EndElement Name: EndElement Node Type:EndElement Name: EndElement Node Type:Element Name: Element -----> LineItem Name: Computer Desk -----> LineItem Price: 499.99 Node Type:EndElement Name: EndElement