The following sections introduce you to the basic terminology and format of Extensible Markup Language (XML) files, including a discussion of the XmlDocument and XmlNode classes, which are part of the System.Xml namespace. You will also learn how you can synchronize data in a DataSet object with data in an XmlDocument object. Using the XmlNode , XmlDocument , XmlTextReader , and XmlTextWriter Classes To understand the .NET Framework representation of an XML document, let's start with the concept of a node. A node is one item in an XML documentit might be an attribute, a comment, an element, or something else. In the System.Xml namespace, nodes are represented by XmlNode objects. Table 7.12 shows the most important members of the XmlNode class. Table 7.12. Important Members of the XmlNode Class Member | Type | Description | AppendChild() | Method | Adds a new child node to the end of this node's list of children. | Attributes | Property | Specifies a collection of the attributes of this node. | ChildNodes | Property | Specifies a collection of child nodes of this node. | FirstChild | Property | Specifies the first child node of this node. | InnerText | Property | Specifies the value of this node and all its children. | InnerXml | Property | Specifies the XML code representing just the children of this node. | InsertAfter() | Method | Inserts a new node after this node. | InsertBefore() | Method | Inserts a new node before this node. | LastChild | Property | Specifies the last child node of this node. | Name | Property | Specifies the name of the node. | NextSibling | Property | Specifies the next child node of this node's parent node. | NodeType | Property | Specifies the type of this node. The XmlNodeType enumeration includes values for all possible node types. | OuterXml | Property | Specifies the XML code representing this node and all its children. | ParentNode | Property | Specifies the parent of this node. | PrependChild() | Method | Adds a new child node to the start of this node's list of children. | PreviousSibling() | Method | Specifies the previous child node of this node's parent node. | RemoveAll() | Method | Removes all children of this node. | RemoveChild() | Method | Removes a specified child of this node. | ReplaceChild() | Method | Replaces a child node with a new node. | Value | Property | Specifies the value of the node. | XmlNode objects are collected into an XmlDocument object. The XmlDocument class provides an in-memory representation of an XML document. Table 7.13 lists the most important members of the XmlDocument class. Table 7.13. Important Members of the XmlDocument Class Member | Type | Description | CreateAttribute() | Method | Creates a new attribute node | CreateElement() | Method | Creates a new element node | CreateNode() | Method | Creates a new XmlNode object | DocumentElement | Property | Returns the XmlNode object that represents the root node of this document | GetElementsByTagName() | Method | Returns a list of all elements with the specified tag name | Load() | Method | Loads an XML document into an XmlDocument object | LoadXml() | Method | Loads a string of XML data into an XmlDocument object | Save() | Method | Saves the XmlDocument object as a file or stream | WriteTo() | Method | Saves the XmlDocument object to an XmlWriter object | Follow these steps to learn how to read the contents of an XML document: -
Add a new Visual C# ASP.NET Web Application project ( Example7_3 ) to the current solution. -
Add a new XML file ( BobsTractors.xml ). Enter this text in the new file and then save the file: <?xml version="1.0" encoding="UTF-8"?> <!-- Customer list for Bob's Tractor Parts --> <Customers> <Customer CustomerNumber="1"> <CustomerName>Lambert Tractor Works </CustomerName> <CustomerCity>Millbank</CustomerCity> <CustomerState>WA</CustomerState> </Customer> <Customer CustomerNumber="2"> <CustomerName><![CDATA[Joe's Garage]]> </CustomerName> <CustomerCity>Doppel</CustomerCity> <CustomerState>OR</CustomerState> </Customer> </Customers> -
Place a Button control ( btnLoadXml ) and a ListBox control ( lbNodes ) on the form. -
Switch to Code view and add the following using directives: using System.Xml; using System.IO; -
Double-click the Button control and enter this code to load data when the button is clicked: private void btnLoadXml_Click(object sender, System.EventArgs e) { // Hook up to the disk file XmlTextReader xtr = new XmlTextReader( Server.MapPath("BobsTractors.xml")); xtr.WhitespaceHandling = WhitespaceHandling.None; XmlDocument xd = new XmlDocument(); // Load the file into the XmlDocument xd.Load(xtr); // Add an item representing the document to the ListBox lbNodes.Items.Add("XML Document"); // Find the root node, and add it together with its children XmlNode xnod = xd.DocumentElement; AddWithChildren(xnod, 1); } private void AddWithChildren(XmlNode xnod, Int32 intLevel) { // Adds a node to the ListBox, together with its children. // intLevel controls the depth of indenting XmlNode xnodWorking; string strIndent = ""; for (int i=0; i< 2*intLevel; i++) strIndent += " "; // Get the value of the node (if any) String strValue= (String) xnod.Value; if(strValue != null) strValue = " : " + strValue; // Add the node details to the ListBox string str = strIndent + xnod.Name + strValue; StringWriter writer = new StringWriter(); Server.HtmlDecode(str, writer); lbNodes.Items.Add(writer.ToString()); // For an element node, retrieve the attributes if(xnod.NodeType == XmlNodeType.Element) { XmlNamedNodeMap mapAttributes= xnod.Attributes; // Add the attributes to the ListBox foreach(XmlNode xnodAttribute in mapAttributes) { str = strIndent + " " + xnodAttribute.Name + " : " + xnodAttribute.Value; writer = new StringWriter(); Server.HtmlDecode(str, writer); lbNodes.Items.Add(writer.ToString()); } // If there are any child nodes, call this procedure recursively if(xnod.HasChildNodes) { xnodWorking = xnod.FirstChild; while (xnodWorking != null) { AddWithChildren(xnodWorking, intLevel + 1); xnodWorking = xnodWorking.NextSibling; } } } } -
Set the Web project as the startup project for the solution and run the application. Click the button. The contents of the XML file will be dumped to the ListBox control. | The Server.MapPath() method takes a relative virtual path for a file and returns its physical path . Remember, all the ASP.NET code is running on the server, so any file paths must make sense in the context of the server's file system. | The code in the previous example uses an XmlTextReader object to read the disk file into the XmlDocument object. The code uses the DocumentElement property of the XmlDocument object to find the node at the root of the tree representation of the XML document. After that, it's just a matter of recursively calling a procedure that adds information about the node to the ListBox control. One bit of added complexity in the code is necessary to deal with attributes. Attribute nodes are not included in the ChildNodes collection of a node in the XmlDocument object. Instead, you can use the Attributes property of the XmlNode object to get a collection of attribute nodes only. The code uses an XmlNamedNodeMap object to hold this collection; this object can hold an arbitrary collection of XmlNode objects of any type. You can also modify an XML document through the XmlDocument object. To do so, you need to modify the individual XmlNode objects and then write the file back to disk as shown in the following code segment: // Write the modified file to disk XmlTextWriter xtw = new XmlTextWriter( Server.MapPath("BobsTractors.new.xml"), System.Text.Encoding.UTF8); xd.WriteTo(xtw); xtw.Flush(); xtw.Close(); | When you have to read data fast in a forward-only manner and memory is a constraint, you should use XmlTextReader . When memory is not a constraint and you want flexibility for inserting, deleting, and updating data in any direction, you should use XmlDocument . | Treating XML As Relational Data You can treat an XML document as relational data. To do this, you can use the XmlDataDocument class, which inherits from XmlDocument . The key feature of the XmlDataDocument class is that it can be synchronized with a DataSet object. For example, consider the following code segment that reads the BobsTractor.xml file and populates a DataGrid control: // Create an XmlTextReader object to read the file XmlTextReader xtr = new XmlTextReader(Server.MapPath("BobsTractors.xml")); XmlDataDocument xdd = new XmlDataDocument(); // Get the DataSet DataSet ds = xdd.DataSet; // Read the schema of the file to initialize the DataSet ds.ReadXmlSchema(xtr); xtr.Close(); xtr = new XmlTextReader(Server.MapPath("BobsTractors.xml")); xtr.WhitespaceHandling = WhitespaceHandling.None; // Load the file into the XmlDataDocument xdd.Load(xtr); xtr.Close(); // And display it on the DataGrid dgXml.DataSource = ds; dgXml.DataBind(); For the DataSet object to properly represent the XML, it must have the same schema (structure) as the XML file. In the previous code segment, I've ensured this by using the ReadXmlSchema() method of the DataSet object to load the schema from the same XML file the XmlDataDocument object holds. The XmlTextReader object has to be closed and reopened after the schema is read because it's a forward-only object. The synchronization between the XmlDataDocument object and the DataSet object is two way. If you derive a dataset object from an XmlDataDocument object, modify the dataset object, and then write the XmlDataDocument object back to disk, the changes you made in the DataSet object are reflected in the XML file. | If you already have a DataSet object in your code, you can create the equivalent XML document by calling an overloaded constructor of the XmlDataDocument class, like so: XmlDataDocument xdd = new XmlDataDocument(ds); | |