|
101 Microsoft Visual Basic. NET Applications Authors: Campbell S., Swigart S., Carver B. Published year: 2006 Pages: 47/157 |
One of the most common ways to work with XML is via its Document Object Model, or DOM. The .NET Framework provides DOM-style support via classes in the System.Xml namespace. This sample application shows you numerous ways to work with the XML DOM. Through a series of examples, you’ll become familiar with the XmlDocument class and the classes derived from the abstract XmlNode class. Figure 3-21 shows Application #28 in action.
Figure 3-21:
Application #28.
|
|
Application #3: String Manipulation
Application #4: Try/Catch/Finally
|
|
An XmlDocument object represents an in-memory (cached) XML document that has been parsed as a tree of nodes to enable navigation and manipulation of its contents. According to the W3C specifications, each item in an XML document—whether it is an Element, Attribute, Text, etc.—is known as a node. Nodes are represented by the abstract XmlNode class. The XmlDocument class also extends XmlNode . You can get an idea of the various types of nodes that make up an XML document by perusing the members of the XmlNodeType enumeration.
For example, consider the following simple XML document. Figure 3-22 shows how the document would be loaded into the DOM.
<?xml version="1.0"?>
<books>
<book>
<author>Carson</author>
<price format="dollar">31.95</price>
<pubdate>05/01/2001</ pubdate >
</book>
<pubinfo>
<publisher>MSPress</publisher>
<state>WA</state>
</pubinfo>
</books>
Figure 3-22:
This figure shows how the memory is structured when the
preceding
XML data is read into the DOM structure (source: .NET Framework SDK Documentation).
Thus, working with XML using the DOM begins with becoming familiar with the members of the XmlDocument and XmlNode classes.
You’ll now see how to create an XML document programmatically, load an existing XML document, iterate through XML nodes using recursion, and find nodes using XPath expressions to modify their contents.
The XmlDocument class has methods that allow you to programmatically create an XML document. The CreateXmlFile method in the sample application contains code that demonstrates how to do this.
First, variables that represent the major parts of an XML document are declared and initialized . (For all the examples in the sample application, the most commonly used variables—such as xDoc—have already been declared at the class level.)
Dim xPI As XmlProcessingInstruction
Dim xComment As XmlComment
Dim xElRoot, xElFamily As XmlElement
xDoc = New XmlDocument()
You can now begin to build the document. Methods associated with each variable type are aptly named, making the code that follows self-describing :
xPI = xDoc.CreateProcessingInstruction("xml", "version='1.0'")
xDoc.AppendChild(xPI)
xComment = xDoc.CreateComment("Family Information")
xDoc.AppendChild(xComment)
xElRoot = xDoc.CreateElement("xml")
xDoc.AppendChild(xElRoot)
The only thing that requires some clarification is the use of AppendChild . As its name implies, this causes the passed node to be added to the end of the list of nodes for the document or node calling the method. You might think that CreateElement would suffice, but it only creates the element in memory and doesn’t actually add it to the DOM. Thus AppendChild is conceptually similar to ADO.NET methods such as DataTable.AcceptChanges . Until AcceptChanges is invoked, new rows and other associated changes are not reflected in the DataTable object.
The remaining elements in this simple document are added as follows:
xElRoot = xDoc.CreateElement("xml")
xDoc.AppendChild(xElRoot)
xElFamily = _
CType(xElRoot.AppendChild(xDoc.CreateElement("Family")), XmlElem ent)
xElFamily.AppendChild(xDoc.CreateElement("Father"))
Notice that AppendChild returns a reference to the node that was appended. This comes in handy when adding nodes in succession, as when the Family element is appended and then used in the next line for adding the Father element.
The final step is to save the cached XML in the DOM to a physical file. To do this, the XmlDocument class exposes an overloaded Save method. The overload used here takes the full physical path where the file will either be created or overwritten:
xDoc.Save(strModifyFile)
If you examine the file after saving it, you’ll notice it’s not very readable because of the lack of white space. By default, white space is stripped out when a document is saved. However, you can set the XmlDocument.PreserveWhiteSpace property to True if you want the white space.
The XmlDocument class exposes two methods for loading XML. Load has four overloads that allow you to load XML into the DOM from a Stream object, an XmlReader object, or a TextReader object, or by providing a path to a physical file. In the sample application, the LoadXmlFile routine demonstrates the latter approach.
Alternatively, you can use LoadXml to load from a string. In the sample, LoadXMLFromString creates some XML content using a StreamWriter object and then loads it into the DOM using this line:
xDoc.LoadXml(sw.ToString())
Sometimes there is a need to iterate through all nodes in a document. A good way to do this is with a method that uses recursion. In the sample’s IterateThroughAllNodes method, you see an example of this. After loading a document into the DOM, it invokes a private helper routine named TraverseTreeAndWriteInfo , which takes three arguments: a StreamWriter object, an XmlNode object, and an integer for tracking the node level so that proper indentation can be used to format the output:
Dim xNodeInLoop As XmlNode
Dim s As New String(CChar(vbTab), intLevel)
Dim strValues() As String = {s, xNode.Name, xNode.NodeType.ToString( )}
sw.WriteLine(" ()", strValues)
If xNode.HasChildNodes Then
For Each xNodeInLoop In xNode.ChildNodes
Me.TraverseTreeAndWriteInfo(sw, xNodeInLoop, intLevel + 1)
Next xNodeInLoop
End If
The method determines whether the current node has any children. If it does, it calls itself recursively until all nodes in the document have been traversed. At each level, the node’s name, type, and level are added to the array, which is then written to the StreamWriter object.
There are several ways you can find one or more nodes. The sample application uses XPath in conjunction with the SelectSingleNode and SelectNodes functions. These are exposed by XmlNode and return an XmlNode and XmlNodeList , respectively. In the sample’s ModifyElementValue method, you’ll find code that shows how to use an XPath expression to find an element:
xNode = xDoc.SelectSingleNode("//Person [.=""Gerald L. Smith""]")
If Not (xNode Is Nothing) Then
xEl = CType(xNode, XmlElement)
xEl.InnerText = "Jerry Smith"
End If
The value of this element is then changed by setting the InnerText property to a different string.
In the ModifyAttributeValue method, SelectNodes is used to retrieve an XmlNodeList object containing a collection of Person elements. This list is then iterated through, and the attribute values are changed for each element using SetAttribute :
xNodeList = xDoc.SelectNodes("//Person")
If xNodeList.Count > 0 Then
For Each xNode In xDoc.SelectNodes("//Person")
xEl = CType(xNode, XmlElement)
Select Case xEl.GetAttribute("type")
Case "father"
xEl.SetAttribute("type", "parent")
xEl.SetAttribute("gender", "male")
Case "mother"
xEl.SetAttribute("type", "parent")
xEl.SetAttribute("gender", "
female
")
Case "son"
xEl.SetAttribute("type", "child")
xEl.SetAttribute("gender", "male")
Case "
daughter
"
xEl.SetAttribute("type", "child")
xEl.SetAttribute("gender", "female")
End Select
Next
End If
Another XPath example is in DeleteNodesAndAddNodesWithAttributes . After finding a specific element that has a type attribute equal to parent , the age attribute is deleted and the value of the type attribute is changed to father :
xNode = xDoc.SelectSingleNode("//Person[@type='parent']")
If Not (xNode Is Nothing) Then
xEl = CType(xNode, XmlElement)
xEl.Attributes.RemoveNamedItem("age")
xEl.SetAttribute("type", "father")
End If
Last but not least, another good way to find a node is by its tag name, using the GetElementsByTagName method exposed by both XmlDocument and XmlElement . The following code in the sample’s DisplayElementsByTag routine illustrates the use of this method. After getting a node list, the code iterates through all of its nodes and child nodes, passing information to the StreamWriter object. Notice that to view the actual contents of the element—that is , what is between the element’s tags— the contents were treated as a child of type Text :
xNodeList = xDoc.GetElementsByTagName(strTagSearchExp)
With sw
.WriteLine("All text elements matching '':", strTagSearchExp)
.WriteLine(strLine)
For Each xNode In xNodeList
For Each xNodeChild In xNode.ChildNodes
If xNodeChild.NodeType = XmlNodeType.Text Then
.WriteLine(xNode.Name & ": " & xNodeChild.Value)
End If
Next
Next
End With
For some of you, this might be easier than using XPath. However, it’s more limiting because it returns only elements.
In the .NET Framework, Microsoft continues its extensive XML support with the DOM-style XmlDocument and XmlNode classes. Using these and derived classes, you can easily work with XML loaded into the DOM. After a brief overview of the DOM, you were taken on a quick survey of numerous examples in the sample application that demonstrate how to use the many members associated with these classes.
|
101 Microsoft Visual Basic. NET Applications Authors: Campbell S., Swigart S., Carver B. Published year: 2006 Pages: 47/157 |