Teach Yourself Visual Studio® .NET 2003 in 21 Days [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Teach Yourself Visual Studio® .NET 2003 in 21 Days [Electronic resources] - نسخه متنی

Jason Beres

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







Reading and Writing XML Files


The abstract XmlReader and XmlWriter classes of the System.XML namespace provide reading and writing functionality for XML files. XmlReaders are implemented in three main classes that provide forward-only processing of XML files. Table 12.3 lists the implementations of the XmlReader class.






















Table 12.3. XmlReader Classes in the System.XML Namespace

Class


Description


XmlTextReader


Fastest implementation of XmlReader. It checks for well-formed XML, but doesn't support data validation. This reader cannot expand general entities and doesn't support default attributes.


XmlValidatingReader


Implementation of XmlReader that can validate data using DTDs or schemas. This reader can also expand general entities and supports default attributes.


XmlNodeReader


Implementation of XmlReader that reads XML data from an XmlNode.

The XmlReader classes are noncached forward-only readers. If you need to parse XML in memory, use the XmlDocument class. The XmlDocument class loads an XML file in memory as a tree-like hierarchy, similar to using the DOM objects in the MSXML parser. To work with the different variations of parsing XML files, you're going to write code that uses the different navigation techniques of the XmlWriter, XmlReader, and XmlDocument classes.

Creating the XMLCode Test Form


To the XML application you've been working with, add a new form named XMLCode by right-clicking your project name, selecting Add from the contextual menu, and then selecting Add New Form. Table 12.4 describes the controls and the Text and Name properties you must add to the form. When you're done, your form should look like Figure 12.12.

Figure 12.12. XMLCode form after adding controls.






























































Table 12.4. Controls for the XMLCode Form

Control


Name


Text


CommandButton


GetXmlFromDataSet


Get XML From DataSet


CommandButton


GetXmlDataReader


Get XML DataReader


CommandButton


LoadXmlFromFile


Load XML From File


CommandButton


SimpleXmlTextReader


Simple XmlTextReader


CommandButton


XmlTextReaderByNode


XmlTextReader By Node


CommandButton


XmlTextReaderAttributes


XmlTextReader Attributes


CommandButton


UsingXmlDocument


Using XmlDocument


CommandButton


XPathSelectNodes


XPath SelectNodes


CommandButton


DOMXmlAttributes


DOM XmlAttributes


RichTextBox


XmlOut


Leave Blank

You must also alias the following namespaces in this form:


  • System.Data.SqlClient


  • System.IO


  • System.Text


  • System.Xml



Now that the form is created, you'll write code to create the XML files you'll be working with.

Using a DataSet to Create XML Files and Schemas


Earlier today you created an XML file based on rules you defined in an XML schema file. I mentioned that this could have been done just as easily using methods of the DataSet class. To create an XML file and schema based on the Customers table in the Northwind database, double-click the Get XML from DataSet button and add the code in Listing 12.3.

Listing 12.3 Using the WriteXml and WriteXmlSchema Methods of the DataSet Class



Private Sub GetXmlFromDataSet_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles GetXmlFromDataSet.Click
' Check to see if the files exist, is they do, Delete them
If File.Exists("Customers.xml") Then
File.Delete("Customers.xml")
End If
If File.Exists("CustomersSchema.xml") Then
File.Delete("CustomersSchema.xml")
End If

' Create a DataSet to hold the XML
Dim ds As DataSet = New DataSet("NorthwindCustomers")
' Connect to the database
Dim cn As SqlConnection = New SqlConnection( _
"database=northwind;server=.\NetSDK;Integrated Security=SSPI")
' Set the DataAdapter to get the data
Dim adp As New SqlDataAdapter("Select * from Customers", cn)
' Fill the DataSet with the DataAdapter command
adp.Fill(ds, "Customer")
' call the WriteXml and WriteXmlSchema methods
ds.WriteXml("Customers.xml")
ds.WriteXmlSchema("CustomersSchema.xml")

End Sub



private void GetXmlFromDataSet_Click(object sender, System.EventArgs e)
{
// Check to see if the files exist, is they do, Delete them
if (File.Exists(@"Customers.xml"))
{
File.Delete(@"Customers.xml");
}
if (File.Exists(@"CustomersSchema.xml"))
{
File.Delete(@"CustomersSchema.xml");
}
// Create a DataSet to hold the XML
DataSet ds = new DataSet("NorthwindCustomers");
// Connect to the database
SqlConnection cn = new SqlConnection
(@"database=northwind;server=.\NetSDK;Integrated Security=SSPI");
// Set the DataAdapter to get the data
SqlDataAdapter adp = new SqlDataAdapter("Select * from Customers", cn);
// Fill the DataSet with the DataAdapter command
adp.Fill(ds, "Customer");
// call the WriteXml and WriteXmlSchema methods
ds.WriteXml(@"Customers.xml");
ds.WriteXmlSchema(@"CustomersSchema.xml");
}

Run the application and execute the code you just wrote. If you drill into the Bin directory of the solution, you'll see the two new XML files that your code created. Using the WriteXml and WriteXmlSchema methods of the DataSet class, you created the XML file and XML schema for the Customers table in the Northwind database. If you double-click the XML files in the Solution Explorer, you'll see the XML that was created in the XML designer. You'll notice that using the WriteXml and WriteXmlSchema methods creates XML files using Elementsthere are no attributes in the created files.

To create attribute-based XML files, you can use a DataReader with the For XML Auto clause in T-SQL and a FileStream to generate the XML file.

Using For XML Auto to Create Attribute-Based XML Files


To create an attribute-based XML file, you can use many techniques. The XmlTextWriter class could be used, but there's an easier way. Listing 12.4 demonstrates how to use the For XML Auto Transact-SQL clause to return XML from SQL Server. After the data is returned in a SqlDataReader, you can loop through the data and write it out to a stream. To ensure that the resulting XML is well formed, you add the prolog information and the root element's start and end tags. Double-click on the Get XML DataReader button and add the code in Listing 12.4.

Listing 12.4 Creating an Attribute-Based XML File



Private Sub GetXmlDataReader_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles GetXmlDataReader.Click
' Create a stream to write to
Dim sr As New StreamWriter("CustomerAttributes.xml")

' Add the XML prolog and Root element
sr.WriteLine("<?xml version='1.0' standalone='yes' ?>")
sr.WriteLine("<TransformedCustomers>")
' Connect to the database
Dim cn As SqlConnection = New SqlConnection( _
"database=northwind;server=.\NetSDK;Integrated Security=SSPI")
cn.Open()
' Use the For XML Auto clause
Dim cmd As New SqlCommand("Select * from customers for XML Auto", cn)
' Declare the DataReader to read the data
Dim dr As SqlDataReader = cmd.ExecuteReader
' Loop thru the DataReader, writing out the file
While dr.Read
' Get each chunk of XML as the reader reads it
sr.Write(dr(0))
End While

' Write the End Element
sr.WriteLine("</TransformedCustomers>")
' Flush and Close the Stream
sr.Flush()
sr.Close()
End Sub



private void GetXmlDataReader_Click(object sender, System.EventArgs e)
{
// Create a stream to write to
StreamWriter sr = new StreamWriter(@"CustomerAttributes.xml");
// Add the XML prolog and Root element
sr.WriteLine("<?xml version='1.0' standalone='yes' ?>");
sr.WriteLine("<TransformedCustomers>");

// Connect to the database
SqlConnection cn = new SqlConnection
(@"database=northwind;server=.\NetSDK;Integrated Security=SSPI");
cn.Open();
// Use the For XML Auto clause
SqlCommand cmd = new SqlCommand
(@"Select * from customers for XML Auto", cn);
// Declare the DataReader to read the data
SqlDataReader dr = cmd.ExecuteReader();
// Loop thru the DataReader, writing out the file
while (dr.Read())
{
// Get each chunk of XML as the reader reads it
sr.Write(dr.GetString (0));
}
// Write the End Element
sr.WriteLine("</TransformedCustomers>");
// Flush and Close the Stream
sr.Flush();
sr.Close();
}

If you run the application now and run the GetXMLDataReader code, you'll have a new XML file in your Bin directory named CustomerAttributes.xml. If you compare this file to the Customers.xml file you created in Listing 12.3, you'll see the XML format looks quite different, but the way they are handled in the Data view of the XML Designer is exactly the same. They're both examples of well-formed XML documents.

The amount of actual text, or size in bytes, of an XML file that's purely using elements is much larger than an XML file created using attributes. If the amount of data being passed over the wire is critical, you should consider using attributes for flat XML files instead of elements.

The ReadXml method of the DataSet you used earlier to load the Employees.xml file behaves the same for XML documents based on elements or attributes.

To read the complete XML file as a stream, you can use the GetXml method of the DataSet class. Listing 12.5 loads the Customers.xml file into a DataSet, and then uses the GetXml method of the DataSet class to display the data in the textbox. Add the code in Listing 12.5 to the LoadXml click event.

Listing 12.5 Loading XML to a String Using the ReadXml and GetXml Methods of the DataSet Class



Private Sub LoadXMLFile_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles LoadXMLFile.Click
' Create a new DataSet
Dim ds As New DataSet()
' Load the XML file into the DataSet with the ReadXml method
ds.ReadXml("Customers.xml")
' Send the XML to the textbox
XmlOut.Text = ds.GetXml()
End Sub



private void LoadXMLFile_Click(object sender, System.EventArgs e)
{
// Create a new DataSet
DataSet ds = new DataSet();
// Load the XML file into the DataSet with the ReadXml method
ds.ReadXml(@"Customers.xml");
// Send the XML to the textbox
XmlOut.Text = ds.GetXml();
}

In Listing 12.5, the ReadXml method is used to fill the DataSet with the data from the XML file. After the DataSet is loaded, the GetXml method is called to output the XML data to the text box. When you run the application and execute the code, the data from the XML file is simply displayed in the text box, and you should see something similar to Figure 12.13.

Figure 12.13. Output from the GetXml method of the DataSet class.


After an XML file is loaded into the DataSet, you can treat it like any other DataTable in the DataSet. You can loop through tables, rows, and columns just as you did over the last two days when you learned how to work with DataSets in ADO.NET. Remember that XML is data. After data is in a DataSet, the methods to interact with it are the same no matter what the datasource is.

Using the XmlTextReader Class


The XmlTextReader class can be compared to the DataReader class of the System.Data namespace. DataReaders are read-only, forward-only unbuffered streams of data from a database. XmlReaders are read-only, forward-only unbuffered streams of data from XML files. The XmlTextReader class provides robust functionality for reading XML files that are element based or attribute based.

The Read method of the XmlTextReader class reads the XML stream until a False value is returned to indicate the end of the file has been reached. While reading the file, you can check the NodeType property to determine what node you're reading and what kind of node it is. Table 12.5 lists the NodeType enumeration and descriptions of the different types of nodes.


















































































Table 12.5. The NodeType Enumeration

Node Name


Description


Attribute


An Attribute node can have the following child node types: Text and EntityReference. The Attribute node doesn't appear as the child node of any other node type. It isn't considered a child node of an Element.


CDATA


CDATA sections are used to escape blocks of text that would otherwise be recognized as markup. A CDATA node cannot have any child nodes. It can appear as the child of the DocumentFragment, EntityReference, and Element nodes.


Comment


A Comment node can't have any child nodes. It can appear as the child of the Document, DocumentFragment, Element, and EntityReference nodes.


Document


A document object that, as the root of the document tree, provides access to the entire XML document. A Document node can have the following child node types: XmlDeclaration, Element (maximum of one), ProcessingInstruction, Comment, and DocumentType. It can't appear as the child of any node types.


DocumentFragment


A document fragment. The DocumentFragment node associates a node or subtree with a document without actually being contained within the document. A DocumentFragment node can have the following child node types: Element, ProcessingInstruction, Comment, Text, CDATA, and EntityReference. It can't appear as the child of any node types.


DocumentType


A DocumentType node can have the following child node types: Notation and Entity. It can appear as the child of the Document node.


Element


An Element node can have the following child node types: Element, Text, Comment, ProcessingInstruction, CDATA, and EntityReference. It can be the child of the Document, DocumentFragment, EntityReference, and Element nodes.


EndElement


Returned when XmlReader gets to the end of an element.


EndEntity


Returned when XmlReader gets to the end of the entity replacement as a result of a call to ResolveEntity.


Entity


An Entity node can have child nodes that represent the expanded entity (for example, Text and EntityReference nodes). It can appear as the child of the DocumentType node.


EntityReference


An EntityReference node can have the following child node types: Element, ProcessingInstruction, Comment, Text, CDATA, and EntityReference. It can appear as the child of the Attribute, DocumentFragment, Element, and EntityReference nodes.


None


This is returned by the XmlReader if a Read method hasn't been called.


Notation


A Notation node can't have any child nodes. It can appear as the child of the DocumentType node.


ProcessingInstruction


A ProcessingInstruction node cannot have any child nodes. It can appear as the child of the Document, DocumentFragment, Element, and EntityReference nodes.


SignificantWhitespace


White space between markup in a mixed content model or white space within the xml:space="preserve" scope.


Text


The text content of a node. A Text node can't have any child nodes. It can appear as the child node of the Attribute, DocumentFragment, Element, and EntityReference nodes.


Whitespace


White space between markup.


XmlDeclaration


The XmlDeclaration node must be the first node in the document. It can't have child nodes. It is a child of the Document node. It can have attributes that provide version and encoding information.

To implement a simple XmlTextReader that outputs only the text or data value for a node, you can use the NodeType as the XmlReader reads the XML stream. The code in Listing 12.6 uses an XmlTextReader to read the Customers.xml file to output only Text node types. Add the code in Listing 12.6 to the Simple XmlTextReader click event.

Listing 12.6 Implementing a Simple XmlTextReader and Checking the NodeType Property



Private Sub SimpleXmlTextReader_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles SimpleXmlTextReader.Click
' Load the XML file into a new XmlTextReader
Dim xr As New XmlTextReader("Customers.xml")
Dim sb As New StringBuilder()
' Read the file, getting the Text nodes, which is the actual data
While xr.Read
' Check the XmlNodeType enumeration for Text
If xr.NodeType = XmlNodeType.Text Then
' Get the Value of the Text nodetype
sb.Append(xr.Value)
' Append the carriage return
sb.Append(ControlChars.CrLf)
End If
End While
' Output to the textbox
XmlOut.Text = sb.ToString
' Close the XmlTextReader
xr.Close()

End Sub



private void SimpleXmlTextReader_Click
(object sender, System.EventArgs e)
{
// Load the XML file into a new XmlTextReader
XmlTextReader xr = new XmlTextReader(@"Customers.xml");
StringBuilder sb = new StringBuilder();
// Read the file, getting the Text nodes, which is the actual data
while (xr.Read())
{
// Check the XmlNodeType enumeration for Text
if (xr.NodeType == XmlNodeType.Text)
{
// Get the Value of the Text nodetype
sb.Append(xr.Value + "\n");
}
}
// Output to the textbox
XmlOut.Text = sb.ToString();
// Close the XmlTextReader
xr.Close();
}

After you call the Read method in Listing 12.6, you check the NodeType property. If NodeType is equal to NodeType.Text, the value is appended to the string builder. If you run the application and execute the code, you'll see something similar to Figure 12.14.

Figure 12.14. The XmlReader outputting only Text NodeTypes.


By outputting only the Text node type, you're getting rid of the XML tags that describe the data.

If you need to output specific data, such as the CompanyName, you can check the Name property of the current element. The code in Listing 12.7 reads each element, and adds only the CompanyName values to the string builder for output to the text box. Add the code in Listing 12.7 to the XmlTextReaderByNode click event.

Listing 12.7 Reading XML Elements by Name



Private Sub XmlTextReaderByNode_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles XmlTextReaderByNode.Click
' Load the XML File
Dim xr As New XmlTextReader("Customers.xml")
Dim sb As New StringBuilder()
' Retrieve data based on a specific Node Name
While xr.Read
' Ignore any non-character data
If xr.ReadString.Length > 0 Then
' Check the name of the Element
If xr.Name = "CompanyName" Then
' Read the String with the ReadString() method
sb.Append(xr.ReadString())
' Append the carriage return
sb.Append(ControlChars.CrLf)
End If
End If
End While
' Display in the textbox
XmlOut.Text = sb.ToString
End Sub



private void XmlTextReaderByNode_Click
(object sender, System.EventArgs e)
{
// Load the XML file into a new XmlTextReader
XmlTextReader xr = new XmlTextReader(@"Customers.xml");
StringBuilder sb = new StringBuilder();
// Read the file, getting the Text nodes, which is the actual data
while (xr.Read())
{
// Ignore any non-character data
if (xr.ReadString().Length > 0)
{
// Check the name of the Element
if (xr.Name == "CompanyName")
{
// Read the String with the ReadString() method
sb.Append(xr.ReadString() + "\n");
}
}
}
// Output to the textbox
XmlOut.Text = sb.ToString();
// Close the XmlTextReader
xr.Close();
}

When you run this code, you get only the CompanyName values from the XML file, as Figure 12.15 demonstrates.

Figure 12.15. Retrieving elements by name using the XmlTextReader class.


Using the Name property along the with NodeType is extremely useful for getting data values for specific elements.

Working with Attributes and the XmlTextReader


Until now, you've used only the element-based Customers.xml file. But you'll often need to deal with attributes in an XML file. Using the GetAttribute method of the XmlTextReader class returns a specific attribute in a node.

When the reader reads a node using the Read method, it reads all the information in the node. So, if there are attributes in the node, it looks at them as a collection. By checking the HasAttributes and AttributesCount properties, you can determine whether a node has attributes, and use the GetAttributes method to grab the data values for the attributes you're looking for.

Listing 12.8 uses the GetAttributes method to accomplish the same thing that Listing 12.7 did: retrieve CompanyName. The difference is that the XML file you're reading is the attribute-based file, not the element-based file. The code iterates through all the attributes for each node and outputs them to the text box. Add the code in Listing 12.8 to the XmlTextReaderAttributes click event.

Listing 12.8 Using the GetAttributes Method



Private Sub XmlTextReaderAttributes_Click
(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles XmlTextReaderAttributes.Click
' Load the XML file into a new XmlTextReader
Dim xr As New XmlTextReader("CustomerAttributes.xml")
Dim sb As New StringBuilder()
' Read the file
While xr.Read
' Only look at Elements
If xr.NodeType = XmlNodeType.Element Then
' That have attributes
If xr.HasAttributes Then
' With an AttributeCount > 0
If xr.AttributeCount > 0 Then
sb.Append(ControlChars.CrLf)
' Write out the CompanyName
sb.Append(xr.GetAttribute("CompanyName"))
sb.Append(ControlChars.CrLf)
' Loop thru the Attributes and write them out
Dim intX As Integer
For intX = 0 To xr.AttributeCount - 1
sb.Append("***")
' Get the Attribute
sb.Append(xr.GetAttribute(intX))
sb.Append(ControlChars.CrLf)
Next
End If
End If
End If
End While
' Output to the textbox
XmlOut.Text = sb.ToString
'Console.WriteLine(sb.ToString)
' Close the XmlTextReader
xr.Close()
End Sub



private void XmlTextReaderAttributes_Click
(object sender, System.EventArgs e)
{
// Load the XML file into a new XmlTextReader
XmlTextReader xr = new XmlTextReader(@"CustomerAttributes.xml");
StringBuilder sb = new StringBuilder();
// Read the file, getting the Text nodes, which is the actual data
while (xr.Read())
{
// Only look at Elements
if (xr.NodeType == XmlNodeType.Element)
{
// That have attributes
if (xr.HasAttributes)
{
// With an AttributeCount > 0
if (xr.AttributeCount > 0)
{
// Write out the CompanyName
sb.Append(xr.GetAttribute("CompanyName"));
for (int i = 0; i < xr.AttributeCount; i++)
{
sb.Append("***");
sb.Append(xr.GetAttribute(i) + "\n");
}
}
}
}
}
// Output to the textbox
XmlOut.Text = sb.ToString();
// Close the XmlTextReader
xr.Close();
}

The code in Listing 12.8 first checks to see whether the current node has attributes. If it does, the code makes sure that the count is greater then zero, and then loops through the attributes using the index of the attribute within the node. If you run this now and execute the code, you'll see something like Figure 12.16.

Figure 12.16. Using attributes with the XmlTextReader class.


Reading attributes is just as easy as reading elements in an XML file. More complex XML files use a combination of elements and attributes to describe the data, so understanding how to work with each type of node is important.

/ 270