.NET中使用DOM 1
XML和ADO.NET 3
XPathNavigator 5
XML中串行化对象 6
读写DiffGram 13
.NET中使用DOM
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
XmlNodeList nodeLst = doc.GetElementsByTagName("title");
foreach (XmlNode node in nodeLst)
listBox1.Items.Add(node.InnerText); // InnerXml / OuterXml
如何插入节点
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
XmlElement newBook = doc.CreateElement("book");
newBook.SetAttribute("genre", "Mystery");
newBook.SetAttribute("publicationdate", "2001");
newBook.SetAttribute("ISBN", "123456789");
XmlElement newTitle = doc.CreateElement("title");
newTitle.InnerText = "Case of the Missing Cookie";
newBook.AppendChild(newTitle);
XmlElement newAuthor = doc.CreateElement("author");
newBook.AppendChild(newAuthor);
XmlElement newName = doc.CreateElement("name");
newName.InnerText = "Cookie Monster";
newAuthor.AppendChild(newName);
XmlElement newPrice = doc.CreateElement("price");
newPrice.InnerText = "9.95";
newBook.AppendChild(newPrice);
doc.DocumentElement.AppendChild(newBook);
XmlTextWriter tr = new XmlTextWriter("booksEdit.xml", null);
tr.Formatting = Formatting.Indented;
//保存当前节点和子节点
doc.WriteContentTo(tr);
//只保存当前节点
//_doc.WriteTo(tr);
//_doc.Save(tr);
tr.Close();
XmlNodeList nodeLst = doc.GetElementsByTagName("title");
foreach (XmlNode node in nodeLst)
listBox1.Items.Add(node.InnerText);
SelectSingleNode() 和SelectNodes() 都是在XmlNode中定义的,而XmlDocument是基于XmlNode的.
SelectSingleNode()返回一个XmlNode; SelectNodes()返回一个XmlNodeList;
XmlNode node = doc.SelectSingleNode("bookstore/book[title='VC深入浅出']");
XmlNodeList nodeLst = doc.SelectNodes("/bookstore/book/title");
如果要写入XML流的数据已经准备好,最好选择XmlTextWriter;如果只是建立XML文档的一小部分或是在不同的地方插入节点,最好用XmlDocument.希望有一个流类型的模型时,可以使用XmlReader;基于XmlDocument的XmlNode也能遍历XML,虽然灵活性高,但要求的内存较多;
XML和ADO.NET
将ADO.NET数据转换成XML文档
XmlDocument doc = new XmlDocument();
MemoryStream memStrm = new MemoryStream();
//将数据表转换成XML,并放入内存流,使用流的好处是不需要将数据写入磁盘,并还能使用基本Stream类的其它对象.
//WriteXml重载方法中,其中一个方法需要一个XmlWriteMode的枚举参数;
ds.WriteXml(memStrm, XmlWriteMode.IgnoreSchema);
memStrm.Seek(0, SeekOrigin.Begin);
doc.Load(memStrm);
//936 = GB2312
XmlTextWriter wrt = new XmlTextWriter("Product.xml", System.Text.Encoding.GetEncoding(936));
wrt.Formatting = Formatting.Indented;
doc.WriteContentTo(wrt);
XmlWriteMode枚举
成员名称 |
说明 |
DiffGram |
作为 DiffGram 写入整个 DataSet,包括原始值和当前值。若要生成只包含已更改的值的 DiffGram,请调用 GetChanges,然后在返回的 DataSet 上作为 DiffGram 调用 WriteXml。 |
IgnoreSchema |
以 XML 数据形式写入 DataSet 的当前内容,不带 XSD 架构。如果无数据加载到 DataSet 中,则不写入任何内容。 |
WriteSchema |
以 XML 数据形式写入 DataSet 的当前内容,以关系结构作为内联 XSD 架构。如果 DataSet 只有架构而无数据,那么只写入内联架构。如果 DataSet 没有当前架构,则不写入任何内容。 |
上例中先将XML放入流,然后再调用WriteContentTo()方法写入磁盘,其实你也可以直接调用WriteXml()方法,直接
将XML文件写入磁盘. 如果你只需要将DataSet中的表架构转换成XML,那你可以使用 WriteXmlSchema() 方法.
ds.WriteXml("sample.xml", XmlWriteMode.WriteSchema);
上例中,使用了XmlDocument的对象doc,不过将被转换后的XML读入doc的过程过于复杂,先要创建一个流,然后再调用WriteXml()方法写入流,最后再调用Load()方法.其实.NET已经提供了XmlDataDocument专门为XML和ADO.NET服务. XmlDocument的参数是一个DataSet的对象,实际上,如果没有参数,它还是会创建一个名为NewDataSet的DataSet,其中Tables中没有任何表,并且你还可以在创建后设置DataSet属性.
XmlDocument doc = new XmlDocument();
doc = new XmlDataDocument(ds);
如果DataSet中有多个表,并且表之间存在着Relations,怎么办?其实,工作方式仍旧是酱紫.
ds.Relations.Add(ds.Tables["Client"].Columns["客户ID"],
ds.Tables["Order"].Columns["客户ID"]);
//注意,此处生成的Product.xml是带有架构的
ds.WriteXml("Product.xml", XmlWriteMode.WriteSchema);
将XML文档转换成ADO.NET数据
ds.ReadXml("Product.xml");
ReadXml()重载方法中,其中有方法需要用到XmlReadMode枚举(查问MSDN);如果你只需要读取架构,那可以直接调用ReadXmlSchema()方法.
XPathNavigator
XPathNavigator用于从XML文档中选择、迭代、编辑数据. 使用XPathDocument 创建XPathNavigator 对象,该对象为只读, 使用XmlDocument 创建XPathNavigator 对象,该对象为可编辑. XPathNavigator 对象的只读或可编辑状态是使用XPathNavigator 类的CanEdit 属性决定的。
//使用XPathDocument创建的对象只能处于只读状态
XPathDocument doc = new XPathDocument("books.xml");
// XPathNavigator包含了移动和选择所需元素的所有方法
XPathNavigator nav = ((IXPathNavigable)doc).CreateNavigator();
// XPathNodeIterator迭代器,由Select()方法返回,可以看作 XPath中的NodeList或NodeSet
XPathNodeIterator iter = nav.Select("/bookstore/book[@genre='novel']");
//MoveNext():移动到匹配XPath表达式的下一个节点上.但是,最初调用MoveNext()之后,定位在第一个节点上.
while (iter.MoveNext())
{
//SelectDescendants : 选择当前节点的子代节点中与选择条件匹配的所有子代节点。
XPathNodeIterator newIter = iter.Current.SelectDescendants(XPathNodeType.Element, false);
// MoveNext() :移动到匹配XPath表达式的下一个节点上,创建XPathNodeIterator
while (newIter.MoveNext())
listView1.Items.Add(newIter.Current.Name + ": " + newIter.Current.Value);
}
如何像聚合函数一样,将所有书的价格相加?
listView1.Items.Add("Total Cost = " + nav.Evaluate("sum(/bookstore/book/price)"));
如何插入节点?
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
//XPathNavigator对象由XmlDocument对象创建,故处于可编辑状态
XPathNavigator nav = doc.CreateNavigator();
if (nav.CanEdit)
{
XPathNodeIterator iter = nav.Select("/bookstore/book/price");
//MoveNext():移动到匹配XPath表达式的下一个节点上.但是,最初调用MoveNext()之后,定位在第一个节点上.
while (iter.MoveNext())
{
//在每一个<price> </price> 后面插入
iter.Current.InsertAfter("<disc>5</disc>");
}
}
doc.Save("newbooks.xml");
XML中串行化对象
System.Xml.Serialization命名空间中最重要的类是XmlSerializer.串行化一个对象,首先需要实例化一个XmlSerializer对象,并指定串行化的对象类型,然后实例化一个流/写入器对象,把文件写入流/文档,最后调用Serializer()方法.
Product pd = new Product();
pd.ProductID = 200;
pd.CategoryID = 100;
pd.Discontinued = false;
pd.ProductName = "Serialize Objects";
……
XmlSerializer sr = new XmlSerializer(typeof(Product));
TextWriter tr = new StreamWriter("Product.xml");
//Serialize()方法有9个重载,但每一个方法都需要一个写入数据的流,可以是Stream,TextWriter或XmlWriter
sr.Serialize(tr, pd);
// XmlRootAttribute、XmlElementAttribute和XmlAttributeAttribute 是C#的属性,仅是一些声明信息,在运行
//期间由CLR获取.
// XmlRootAttribute把这个类,在串行化生成的XML文档中,标识为根元素
[System.Xml.Serialization.XmlRootAttribute()]
public class Product
{
private int prodId;
private string prodName;
private int suppId;
……
// 这里是XmlAttributeAttribute
[XmlAttributeAttribute(AttributeName = "Discount")]
public int Discount
{
get { return disc; }
set { disc = value; }
}
// XmlElementAttribute把下面的成员看做一个XML元素
[XmlElementAttribute()]
public int ProductID
{
get { return prodId; }
set { prodId = value; }
}
[XmlElementAttribute()]
public string ProductName
{
get { return prodName; }
set { prodName = value; }
}
[XmlElementAttribute()]
public int SupplierID
{
get { return suppId; }
set { suppId = value; }
}
}
Product.xml
<?xml version="1.0" encoding="utf-8"?>
<Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Discount="0">
<ProductID>200</ProductID>
<ProductName>Serialize Objects</ProductName>
<SupplierID>1</SupplierID>
<CategoryID>100</CategoryID>
<QuantityPerUnit>6</QuantityPerUnit>
<UnitPrice>1000</UnitPrice>
<UnitsInStock>10</UnitsInStock>
<UnitsOnOrder>0</UnitsOnOrder>
<ReorderLevel>1</ReorderLevel>
<Discontinued>false</Discontinued>
</Product>
反串行化操作
Product newPd;
FileStream f = new FileStream("Product.xml", FileMode.Open);
XmlSerializer newSr = new XmlSerializer(typeof(Product));
//Deserialize()方法必须有一个流/读取器参数
newPd = (Product)newSr.Deserialize(f);
f.Close();
更为复杂的操作
派生的类+返回一个数据的属性
可以看出,最后只需要串行化Inventory这个类,串行化它,就需要插入一个属性,该属性为每个要添加到数据中的类型包含一个XmlArrayItem构造函数(XmlArrayItem是由XmlArrayItemAttribute类表示的.NET属性名)
XmlArrayItem构造函数的第一个参数是串行化过程中,XML中的元素名,如果不写,默认会与对象类型名相同;第二个参数是对象的类型;
public class Inventory
{
private Product[] stuff;
public Inventory() { }
[XmlArrayItem("Prod", typeof(Product)),XmlArrayItem("Book", typeof(BookProduct))]
public Product[] InventoryItems
{
get { return stuff; }
set { stuff = value; }
}
}
public class BookProduct : Product
{
private string isbnNum;
public BookProduct() { }
public string ISBN
{
get { return isbnNum; }
set { isbnNum = value; }
}
}
private void button4_Click(object sender, EventArgs e)
{
// XmlAttributes: 表示一个属性对象的集合
//第一步:创建一个XmlAttributes对象,为每个要重写的数据类型创建一个XmlElementAttribute对象
XmlAttributes attrs = new XmlAttributes();
attrs.XmlElements.Add(new XmlElementAttribute("Book", typeof(BookProduct)));
attrs.XmlElements.Add(new XmlElementAttribute("Prod", typeof(Product)));
//第二步:创建XmlAttributeOverrides对象
XmlAttributeOverrides attrOver = new XmlAttributeOverrides();
//本例中是要重写Inventory类中的InventoryItems成员
attrOver.Add(typeof(Inventory), "InventoryItems", attrs);
Product newProd = new Product();
BookProduct newBook = new BookProduct();
newProd.ProductID = 100;
newProd.ProductName = "Product Thing";
newProd.SupplierID = 10;
newBook.ProductID = 101;
newBook.ProductName = "How to Use Your New Product Thing";
newBook.SupplierID = 10;
newBook.ISBN = "123456789";
Product[] addProd ={ newProd, newBook };
Inventory inv = new Inventory();
inv.InventoryItems = addProd;
TextWriter tr = new StreamWriter("Product.xml");
XmlSerializer sr = new XmlSerializer(typeof(Inventory), attrOver);
sr.Serialize(tr, inv);
tr.Close();
webBrowser1.Navigate(AppDomain.CurrentDomain.BaseDirectory + "//inventory.xml");
}
Product.xml
<?xml version="1.0" encoding="utf-8"?>
<Inventory xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Prod Discount="0">
<ProductID>100</ProductID>
<ProductName>Product Thing</ProductName>
<SupplierID>10</SupplierID>
<CategoryID>0</CategoryID>
<UnitPrice>0</UnitPrice>
<UnitsInStock>0</UnitsInStock>
<UnitsOnOrder>0</UnitsOnOrder>
<ReorderLevel>0</ReorderLevel>
<Discontinued>false</Discontinued>
</Prod>
<Book Discount="0">
<ProductID>101</ProductID>
<ProductName>How to Use Your New Product Thing</ProductName>
<SupplierID>10</SupplierID>
<CategoryID>0</CategoryID>
<UnitPrice>0</UnitPrice>
<UnitsInStock>0</UnitsInStock>
<UnitsOnOrder>0</UnitsOnOrder>
<ReorderLevel>0</ReorderLevel>
<Discontinued>false</Discontinued>
<ISBN>123456789</ISBN>
</Book>
</Inventory>
读写DiffGram
DiffGram是包含数据在编辑对话前后的XML文档.大部分的DBMS都提供了跟踪或用于提交/回滚过程的功能,但如果你使用的DBMS没有提供这些功能,就可以使用DiffGram.
保存带有DiffGram模式的XML文档
ds.Tables[0].Rows[0]["产品名称"] = "新改的";
DataRow dr = ds.Tables[0].NewRow();
dr["产品ID"] = "1231234";
dr["产品名称"] = "新加的";
ds.Tables[0].Rows.Add(dr);
//首先需要保存为一个模式(架构)文件,是为读取DiffGram做准备
ds.WriteXmlSchema("author.xdr");
ds.WriteXml("authdiff.xml", XmlWriteMode.DiffGram);
使用DiffGram模式读取XML文档
DataSet ds = new DataSet();
//读取DiffGram的模式(架构)文件
ds.ReadXmlSchema("author.xdr");
ds.ReadXml("authdiff.xml", XmlReadMode.DiffGram);
author.xdr
<?xml version="1.0" standalone="yes"?>
<xs:schema id="XMLAuthors" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="XMLAuthors" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Authors">
<xs:complexType>
<xs:sequence>
<xs:element name="产品ID" type="xs:int" minOccurs="0" />
<xs:element name="产品名称" type="xs:string" minOccurs="0" />
<xs:element name="单位数量" type="xs:string" minOccurs="0" />
<xs:element name="单价" type="xs:decimal" minOccurs="0" />
<xs:element name="库存量" type="xs:short" minOccurs="0" />
<xs:element name="订购量" type="xs:short" minOccurs="0" />
<xs:element name="再订购量" type="xs:short" minOccurs="0" />
<xs:element name="中止" type="xs:boolean" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
authdiff.xml
<?xml version="1.0" standalone="yes"?>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<XMLAuthors>
<Authors diffgr:id="Authors1" msdata:rowOrder="0" diffgr:hasChanges="modified">
<产品ID>1</产品ID>
<产品名称>新改的</产品名称>
<单位数量>每箱24瓶</单位数量>
<单价>18.0000</单价>
<库存量>39</库存量>
<订购量>0</订购量>
<再订购量>10</再订购量>
<中止>true</中止>
</Authors>
<Authors diffgr:id="Authors2" msdata:rowOrder="1">
<产品ID>2</产品ID>
<产品名称>WaterBox</产品名称>
<单位数量>每箱24瓶</单位数量>
<单价>19.0000</单价>
<库存量>17</库存量>
<订购量>40</订购量>
<再订购量>25</再订购量>
<中止>false</中止>
</Authors>
......
<Authors diffgr:id="Authors70" msdata:rowOrder="69" diffgr:hasChanges="inserted">
<产品ID>1231234</产品ID>
<产品名称>新加的</产品名称>
</Authors>
</XMLAuthors>
<diffgr:before>
<Authors diffgr:id="Authors1" msdata:rowOrder="0">
<产品ID>1</产品ID>
<产品名称>苹果汁</产品名称>
<单位数量>每箱24瓶</单位数量>
<单价>18.0000</单价>
<库存量>39</库存量>
<订购量>0</订购量>
<再订购量>10</再订购量>
<中止>true</中止>
</Authors>
</diffgr:before>
</diffgr:diffgram>