The
DataSet provides an excellent vehicle for transferring data from one or more relational-style rowsets to XML documents and XML schemas, and vice versa. But you can do even better if you are predominantly concerned with accessing data as XML, rather than starting out with relational data.
Figure 11-11 repeats the diagram you saw in the data management introduction chapter:
Figure 11-11:
Chapter 8; the
XmlDataDocument is designed to act as a bridge between relational and XML data.
The only real external difference between an
XmlDocument object and an
XmlDataDocument object is that the latter has a few extra properties and methods. The most useful is the
DataSet property. This returns a reference to an object that contains the data in the XML document, but which is exposed as a
DataSet object. This is a useful read-only property.
Figure 11-12 conceptualizes the way it works:
Figure 11-12:
The XML document can be accessed through various
Reader objects, loaded into an
XmlDataDocument object (as mentioned in Chapter 8), and can also be loaded into a
DataSet .
However, after you load the XML into an
XmlDataDocument object, you can reference a
DataSet object that contains the same data; this is equivalent to reading the data into that
DataSet . More to the point, as you change the data in either the
DataSet or the
XmlDataDocument , the changes are reflected in both. They are completely and automatically synchronized.
This means there is no longer a distinction between the relational or XML types of data – they are just two views of the same data. This works in part because behind the scenes, the .NET Framework data management objects all use XML as their standard persistence format.
Once you've got the data in an
XmlDataDocument , you can access it using any of the techniques available in the relational and XML armories. The next example page demonstrates a few.
The Synchronization of the XmlDataDocument and DataSet objects (
xml-to-dataset.aspx ) example page shown in Figure 11-13 demonstrates some of the features of the integration we've just discussed. It takes an XML document and the matching XSD schema and loads them into a new
XmlDataDocument object. As shown, there are hyperlinks in the page so that you can examine the XML and schema files – they are basically the same ones used in the first couple of examples in this chapter.
Figure 11-13:
Note |
You must run the page in a browser on the web server itself to be able to open the XML document and schema using the physical paths in the hyperlinks in the page. |
After loading the data into the
XmlDataDocument , the code carries out four different tasks with it. It first displays a list of last names of all the authors in our data. We do this first using the standard methods exposed by the XML DOM (as per the W3C recommendations), and then using an
XPathNavigator object with a recursive search function.
Then a
DataGrid control displays all the rows in the table within the
DataSet . Of course, you can get this
DataSet from the
XmlDataDocument object's
DataSet property, but notice how we are already freely mixing our relational and XML terminology.
Finally, if you scroll to the bottom of this page (as shown in Figure 11-14), you'll see a heap of XML. This has been extracted from the
DataSet object, using the
GetElementFromRow method. Using this method, you can pull out specific rows of data and return just those rows as XML. We've got a simple and efficient automated relational-based technique for manipulating data and creating the equivalent XML.
Figure 11-14:
There is a lot of code in this page, as you can confirm if you view the source. However, it is commented and divided into the four tasks being performed, and so is easy enough to follow. In the code listings here, we'll confine ourselves to the features that are relevant to the four tasks, and omit much of the surrounding code ( code that creates links in the page, error messages, and so on). The first step is to create the
XmlDataDocument and load the schema and XML from disk:
'create a new XmlDataDocument object
Dim objXMLDataDoc As New XmlDataDocument()
'load the XML schema into the XmlDataDocument object
objXMLDataDoc.DataSet.ReadXmlSchema(strSchemaPath)
'load the XML file into the XmlDataDocument object
objXMLDataDoc.Load(strXMLPath)
Now you can use the
XmlDataDocument object. First, the code demonstrates that the object behaves like a normal W3C-standard
XMLDocument object by using the
GetElementsByTagname method to create an
XmlNodeList containing all the
<LastName> elements in the document: Then you can iterate through this
NodeList (collection) displaying all the element values:
Dim objNode As XmlNode
Dim strResults As String = "
'create a NodeList collection of all matching child nodes
Dim colElements As XmlNodeList
colElements = objXMLDataDoc.GetElementsByTagName("LastName")
'iterate through the collection getting the values of the
'child #text nodes for each one
For Each objNode In colElements
strResults &= objNode.FirstChild().Value & " "
Next
'then display the result
outDOMResult.innerHTML = strResults
As discussed in Chapter 8, the .NET Framework introduces a new object that can be used to navigate within an XML document. An
XPathNavigator can be created from an XML document object of any type, by calling the
CreateNavigator method of that document object. In the following code, we use an
XPathNavigator to fetch the values of all the
<LastName> elements in the
XmlDataDocument by moving to the root element of the document and then calling a recursive function, which searches each child of the current element in turn looking for matches and extracting the values:
'create a new XPathNavigator object using the XmlDataDocument object
Dim objXPNav As XPathNavigator
objXPNav = objXMLDataDoc.CreateNavigator()
'move to the root element of the document
objXPNav.MoveToRoot()
'and display the result of the recursive 'search' function
outXPNavResult.innerHTML = SearchForElement(objXPNav, "LastName")
Note |
We haven't listed our recursive SearchForElement function again here, as it's identical to the technique used in Chapter 8. |
The next part of the page output is easy to create. The following code shows how to reference the
DataSet property of the
XmlDataDocument object, and from that access the first member of the
Tables collection. This gives us a reference to the default
DataTable within the
DataSet .
We can use this reference to create a
DataView object, and then assign the
DataView to an ASP.NET
DataGrid control that was previously defined within the page. This gives us a picture of the data as a standard relational rowset – just as though we'd filled our
DataSet table using a
Connection ,
Command , and
DataAdapter .
'create a DataView object for the Books table in the DataSet
Dim objDataView As New DataView(objXMLDataDoc.DataSet.Tables(0))
'assign the DataView object to the DataGrid control
dgrResult.DataSource = objDataView
dgrResult.DataBind() 'and bind (display) the data
The final task in this page is to demonstrate how to query the
DataSet to extract individual rows as XML. The
GetElementFromRow method takes as its parameter an object that represents a row in a
DataTable – a
DataRow object. It returns an XML representation of that row.
You can create a reference to the
DataTable in the
DataSet , and then iterate through the rows. For each one, the
GetElementFromRow method of the
XmlDataDocument object is called, which returns an
XmlElement object. You get a string representation of the element from its
OuterXml property and HTML-encode it before displaying it in the page:
'create a DataTable object for the Books table in the DataSet
Dim objDataTable As DataTable = objXMLDataDoc.DataSet.Tables(0)
Dim objRow As DataRow
Dim objXMLElement As XmlElement
'iterate through all the rows in this table
For Each objRow In objDataTable.Rows
'get an XML element that represents this row
objXMLElement = objXMLDataDoc.GetElementFromRow(objRow)
'HTMLEncode it because it contains XML element tags
strResults &= Server.HtmlEncode(objXMLElement.OuterXML) & "<br />"
Next
outFromRowResult.innerHTML = strResults 'and display the result
Interestingly, there is a mirror of this method, named
GetRowFromElement . You can iterate through the elements in an XML document using the DOM methods or an
XPathNavigator to get an
XmlNodeList of element objects, or individual
For each one, the
GetRowFromElement method of the
XmlDataDocument object that holds the document will return a
DataRow object. This can then be accessed to extract field information, or even used to update the original XML document. So now there is even a way to edit an XML document using relational techniques.
objThisRow = objXmlDataDoc.GetRowFromElement(objElement)
objThisRow("MyFieldName") = "This is the new value"