下面要介绍的第一个示例使用ADO.NET、流和XML把Northwind数据库中的一些数据推入DataSet,并从DataSet中加载带有XML的XmlDocument对象,把XML加载到列表框中。为了运行下面几个示例,需要添加如下using语句:
using System.Xml;
using System.Data.SqlClient;
using System.IO;
因为要使用XmlDocument,所以还需要在模块级添加如下代码:
private XmlDocument doc = new XmlDocument();
对于ADO.NET示例,在窗体上添加一个DataGrid,这样就可以在ADO.NET DataSet中查看数据了,因为数据被绑定到网格上。还可以查看生成的XML文档中的数据,这些数据加载到了列表框中。下面是第一个示例的代码,它们在ADOSample1文件夹中:
private void button1_Click(object sender, System.EventArgs e)
{
//create a dataset
DataSet ds = new DataSet("XMLProducts");
//connect to the northwind database and
//select all of the rows from products table
//make sure your login matches your version of SqlServer
SqlConnection conn = new SqlConnection
(@"server=GLYNNJ_CS\NetSDK;uid=sa;pwd=;database=northwind");
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Products",conn);
在创建了SqlDataAdapter对象da 和 DataSet对象ds后,再实例化MemoryStream、StreamReader 和StreamWriter对象。StreamReader 和 StreamWriter使用MemoryStream来浏览XML文档:
MemoryStream memStrm=new MemoryStream();
StreamReader strmRead=new StreamReader(memStrm);
StreamWriter strmWrite=new StreamWriter(memStrm);
使用MemoryStream的原因是不必把数据写入磁盘。还可以使用基于Stream类的其他对象,例如FileStream。接着,填充DataSet,把它绑定到DataGrid上。DataSet中的数据现在应显示在DataGrid中:
da.Fill(ds,"products");
//load data into DataGrid
dataGrid1.DataSource=ds;
dataGrid1.DataMember="products";
下一步是生成XML。调用DataSet 类的WriteXml()方法,它生成一个XML文档。WriteXml有两个重载方法,一个重载方法的参数是带有文件路径和名称的字符串,另一个重载方法的参数是模式。这个模式是一个XmlWriteMode枚举,其值可以是
● IgnoreSchema
● WriteSchema
● DiffGram
如果不希望WriteXml方法把内联模式写入XML文件的开头,就使用IgnoreSchema,如果要写入内联模式,就使用WriteSchema。本节的后面介绍DiffGram。
ds.WriteXml(strmWrite,XmlWriteMode.IgnoreSchema);
memStrm.Seek(0,SeekOrigin.Begin);
//read from the memory stream to an XmlDocument object
doc.Load(strmRead);
//get all of the products elements
XmlNodeList nodeLst=doc.GetElementsByTagName("ProductName");
//load them into the list box
foreach(XmlNode nd in nodeLst)
listBox1.Items.Add(nd.InnerText);
}
private void listBox1_SelectedIndexChanged(object sender,
System.EventArgs e)
{
//when you click on the listbox,
//a message box appears with the unit price
string srch="XMLProducts/products[ProductFTEL=" +
' " '+ listBox1.SelectedItem.ToString() + ' " ' + "]";
XmlNode foundNode=doc.SelectSingleNode(srch);
if(foundNode!=null)
MessageBox.Show(foundNode.SelectSingleNode("UnitPrice").InnerText);
else
MessageBox.Show("Not found");
}
在23-9所示的屏幕图中,可以查看列表框中的数据和绑定的数据网格。
图 23-9
如果只需要该模式,可调用WriteXmlSchema()而不是WriteXml()。这个方法有4个重载方法,第一个重载方法的参数是一个字符串,其中包含了XML文档的路径和文件名,第二个重载方法使用基于XmlWriter类的一个对象。第三个重载方法使用基于TextWriter类的对象。第四个重载方法派生于Stream类。
如果要把XML文档存入磁盘,就应执行下述操作:
string file = "c:\\test\\product.xml";
ds.WriteXml(file);
在磁盘上会生成一个格式正确的XML文档,并可以由另一个流、DataSet来读取,或者由另一个应用程序或网站使用。因为没有指定XmlMode参数,所以这个XmlDocument包含了模式。在本例中,把流作为XmlDocument.Load方法的参数。
准备好XmlDocument后,使用与前面一样的Xpath语句加载listbox。如果仔细查看,会发现listBox1_SelectedIndexChanged事件有了少许变化。它没有显示元素的InnerText,而是使用SelectSingleNode进行另一个XPath搜索,获得UnitPrice元素。所以每次单击列表框中的一个产品时,都会显示一个带有UnitPrice的消息框。现在数据有两个视图,但更重要的是,可以使用两个不同的模型来处理数据。可以使用System.Data命名空间来操纵数据,也可以使用System.XML命名空间来处理数据。这样应用程序就可以有某些非常灵活的设计,因为现在不必把一个对象模型绑定到程序上,这是ADO.NET 和 System.Xml组合的强大之处。相同数据可以有多个视图,访问数据也有多种方式。
下一个示例去掉了3个流,使用内置于System.XML命名空间中的一些ADO功能简化了过程。但需要修改模块级的代码行:
private XmlDocument doc = new XmlDocument();
为:
private XmlDataDocument doc;
这么做的原因是现在使用的是XmlDataDocument。下面的代码在ADOSample2文件夹中:
private void button1_Click(object sender, System.EventArgs e)
{
//create a dataset
DataSet ds=new DataSet("XMLProducts");
//connect to the northwind database and
//select all of the rows from products table
//make changes to connect string to match your login and server name
SqlConnection conn=new SqlConnection
(@"server=GLYNNJ_CS\NetSDK;uid=sa;pwd=;database=northwind");
SqlDataAdapter da=new SqlDataAdapter("SELECT * FROM products",conn);
//fill the dataset
da.Fill(ds,"products");
//load data into grid
dataGrid1.DataSource=ds;
dataGrid1.DataMember="products";
doc=new XmlDataDocument(ds);
//get all of the products elements
XmlNodeList nodeLst=doc.GetElementsByTagName("ProductName");
//load them into the list box
//we'll use a for loop this time
for(int ctr=0;ctr<nodeLst.Count;ctr++)
listBox1.Items.Add(nodeLst[ctr].InnerText);
}
可以看出,把DataSet加载到XML文档中的代码已经进行了简化。它没有使用XmlDocument类,而使用了XmlDataDocument类,这个类是为了使用DataSet对象的数据而专门设计的。
XmlDataDocument基于XmlDocument类,所以它拥有XmlDocument类的所有功能。一个主要区别是XmlDataDocument有重载的构造函数。注意下面的代码实例化了XmlDataDocument对象doc:
doc = new XmlDataDocument(ds);
它的参数是我们创建的DataSet对象ds,从数据集中创建XML文档,而且不必使用Load方法。实际上,如果实例化一个新的XmlDataDocument对象时,不把DataSet作为参数,该XmlDataDocument就会包含一个名为NewDataSet的DataSet,其表集合中没有任何DataTable,在创建了基于XmlDataDocument的对象后,还可以设置一个DataSet属性。
如果下面的代码添加到DataSet.Fill调用的后面:
ds.WriteXml("c:\\test\\sample.xml", XmlWriteMode.WriteSchema);
就会在文件夹C:\test中生成下面的XML文件:
<?xml version="1.0" standalone="yes"?>
<XMLProducts>
<xs:schema id="XMLProducts" xmlns=""
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element FTEL="XMLProducts" msdata:IsDataSet="true">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element FTEL="products">
<xs:complexType>
<xs:sequence>
<xs:element FTEL="ProductID" type="xs:int"
minOccurs="0" />
<xs:element FTEL="ProductName" type="xs:string"
minOccurs="0" />
<xs:element FTEL="SupplierID" type="xs:int"
minOccurs="0" />
<xs:element FTEL="CategoryID" type="xs:int"
minOccurs="0" />
<xs:element FTEL="QuantityPerUnit" type="xs:string"
minOccurs="0" />
<xs:element FTEL="UnitPrice" type="xs:decimal"
minOccurs="0" />
<xs:element FTEL="UnitsInStock" type="xs:short"
minOccurs="0" />
<xs:element FTEL="UnitsOnOrder" type="xs:short"
minOccurs="0" />
<xs:element FTEL="ReorderLevel" type="xs:short"
minOccurs="0" />
<xs:element FTEL="Discontinued" type="xs:boolean"
minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<products>
<ProductID>1</ProductID>
<ProductName>Chai</ProductName>
<SupplierID>1</SupplierID>
<CategoryID>1</CategoryID>
<QuantityPerUnit>10 boxes x 20 bags</QuantityPerUnit>
<UnitPrice>18</UnitPrice>
<UnitsInStock>39</UnitsInStock>
<UnitsOnOrder>0</UnitsOnOrder>
<ReorderLevel>10</ReorderLevel>
<Discontinued>false</Discontinued>
</products>
</XMLProducts>
这里只显示了第一个Products元素。实际的XML文件应包含Northwind数据库中Products表的所有Products元素。