基於流的 XML 處理
.NET Framework 允許你使用 System.Xml 命名空間(以及它的子命名空間)中的一組類來操作 XML 數據。有兩個基於流的類:XmlTextReader 和 XmlTextWriter ,它們對簡單的 XML 處理非常有效。
寫 XML 文件
.NET 通過兩種方式把 XML 數據寫入文件:
- 可以在內存中使用 XmlDocument 或 XDocument 類創建文檔,結束時把它寫入文件。
- 用 XmlTextWrite 直接把文檔寫入流。在你寫數據的時候會逐個節點輸出數據。
- 上述 3 個類都允許把信息寫入任意的流,因此XML數據也可以寫入到其他存儲位置,如數據庫中文本類型字段。
下面的示例演示如何使用 XmlTextWriter 創建一個格式良好的 XML 文件:
private void WriteXml()
{
string xmlFile = Server.MapPath("DvdList.xml");
// 第二個參數可傳遞一個 System.Text.Encoding 編碼
// 傳遞空引用表示使用標准的 UTF-8 編碼
XmlTextWriter writer = new XmlTextWriter(xmlFile, null);
// Formatting.Indented 表示使用縮進
// Formatting.None 表示不應用特殊的格式(默認)
// Indentation 表示縮進 3 空格
writer.Formatting = Formatting.Indented;
writer.Indentation = 3;
// 編寫版本為“1.0”的 XML 聲明
writer.WriteStartDocument();
// 寫出包含指定文本的注釋 <!--...-->
writer.WriteComment("Creaded @ " + DateTime.Now.ToString());
// 寫出具有指定的本地名稱的開始標記
writer.WriteStartElement("DvdList");
writer.WriteStartElement("DVD");
writer.WriteAttributeString("ID", "1");
writer.WriteAttributeString("Category", "Science Fiction");
// 下面這些元素不包含子元素,因此不需要使用 WriteStartElement()
writer.WriteElementString("Title", "The Matrix");
writer.WriteElementString("Director", "Larry Wachowski");
writer.WriteElementString("Price", "18.74");
// 下面這個 Starring 包含一個或多個元素
// 所以要使用 WriteStartElement()
writer.WriteStartElement("Starring");
writer.WriteElementString("Star", "Keanu Reeves");
writer.WriteElementString("Star", "Laurence Fishburne");
// 接着以相反的順序關閉所有打開的標簽
writer.WriteEndElement();
writer.WriteEndElement();
// 再創建另一個 DVD 元素
writer.WriteStartElement("DVD");
writer.WriteAttributeString("ID", "2");
writer.WriteAttributeString("Category", "Drama");
writer.WriteElementString("Title", "Forrest Gump");
writer.WriteElementString("Director", "Robert Zemeckis");
writer.WriteElementString("Price", "23.99");
writer.WriteStartElement("Starring");
writer.WriteElementString("Star", "Tom Hanks");
writer.WriteElementString("Star", "Robin Wright");
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.Close();
}
如果要給它一個唯一的 XML 命名空間標識 XML 文檔,那么元素也需要放到這個命名空間里。如果要這么做,首先要使用 WriteAttributeString()輸出一個 xmlns 特性,通常會把這個特性加到文檔的根元素或第一個使用命名空間的元素上。其次,元素名稱必須使用命名空間前綴限定,WriteStartElement()方法的重載版本可以達到這一目的。
讀取 XML 文件
- 可以使用 XmlDocument、XPathNavigator(只讀)、XDocument 類一次性將文檔加載到內存中。
- XmlTextReader 類(基於流的讀取器),每次讀取文檔的一個節點。
基於流的方法減少了內存負擔,但如果對 XML 文檔執行耗時任務或為了不影響別人訪問這個XML文檔,還是選擇在內存中操作的方式較好。
XmlTextReader 讀取 XML 文件固然簡單,但也是最不靈活的。文件以順序讀取,不能夠像處理內存中 XML 那樣自由的移動到父、子、兄弟節點。
下面的代碼加載源文件,然后開始每次移動一個文檔節點的循環:
private string ReadXml()
{
string xmlFile = Server.MapPath("DvdList.xml");
XmlTextReader reader = new XmlTextReader(xmlFile);
StringBuilder str = new StringBuilder();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
str.Append("Element: <b>").Append(reader.Name).Append("</b><br />");
break;
case XmlNodeType.Text:
str.Append(" - Value: <b>").Append(reader.Value).Append("</b><br />");
break;
case XmlNodeType.XmlDeclaration:
str.Append("Xml Declaration: <b>");
str.Append(reader.Name).Append(" ").Append(reader.Value).Append("</b><br />");
break;
}
if (reader.AttributeCount > 0)
{
while (reader.MoveToNextAttribute())
{
str.Append(" - Attribute: <b>").Append(reader.Name);
str.Append("</b> Value: <b>").Append(reader.Value).Append("</b><br />");
}
}
}
reader.Close();
return str.ToString();
}
使用 XmlTextReader 時,必須盡可能快的結束任務並關閉閱讀器,因為它在文件上有一個鎖。
下面這段代碼以更直觀的方式從 DVD 列表中獲取數據:
private string ReadXml()
{
string xmlFile = Server.MapPath("DvdList.xml");
XmlTextReader reader = new XmlTextReader(xmlFile);
StringBuilder str = new StringBuilder();
reader.ReadStartElement("DvdList");
while (reader.Read())
{
if (reader.Name == "DVD" && reader.NodeType == XmlNodeType.Element)
{
reader.ReadStartElement("DVD");
str.Append("<ul><b>");
str.Append(reader.ReadElementString("Title"));
str.Append("</b><li>");
str.Append(reader.ReadElementString("Director"));
str.Append("</li><li>");
str.Append(string.Format("{0:C}",Decimal.Parse(reader.ReadElementString("Price"))));
str.Append("</li></ul>");
}
}
reader.Close();
return str.ToString();
}