XML解析的其它用途
XML解析并不僅僅局限于Web服務,例如.NET應用程序就能使用XML作為配置信息的存儲方法。你需要做的事情就是擁有一個.MANIFEST文件,它的名稱必須與應用程序的名稱相同,CLR(通用語言運行時)會自動查閱這個文件找到配置信息。
例如,列表1顯示了添加給一個.MANIFEST文件的XML。這個清單告訴CLR使用Windows XP主題信息繪制標準控件(該配置文件不會影響自己繪制的控件)。注意該文件的版本號可能改變,可以在系統的\WINDOWS\WinSxS文件夾下查看當前的版本號。這個并行庫的文件夾的名稱可能類似x86_Microsoft.Windows.Common-Controls_6595b64144clearcase/" target="_blank" >ccf1df_6.0.0.0_x-ww_1382d70a,列表1中顯示的processorArchitecture值最先出現,接著出現名稱(name)值,然后出現publicKeyToken值,最后出現版本(version)值。
列表1..NET.MANIFEST文件依賴XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"
name="ShowMessage"
version="1.0.0.0"
processorArchitecture="x86"
/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
你也可以建立其它類型的配置文件,你的應用程序可以在啟動過程中分析它。這些文件可以包含應用程序執行需要的任何信息。你可以使用這些配置文件代替注冊表設置項。通常,你會發現使用XML文件比使用注冊表少一些錯誤,并且它們也更靈活。例如,把一個用戶從一臺計算機遷移到另一臺計算機的時候,就不一定需要重新配置應用程序,因為設置信息已經出現在該應用程序的目錄中了。在某些角度上,這意味著我們又回到了過去使用INI文件的情形,但是XML文件包含的信息比INI文件多得多,并且會減少一定形式的損壞和配置錯誤。
當結合其它一些技術(例如可擴充樣式表語言轉換,XSLT)的時候,XML可以使Web頁面更容易閱讀。但是,你也能把這類技術應用于內部。例如,很多公司把這種形式的XML作為建立用戶使用的幫助文件的一種方法。這種幫助信息作為XML文件中的數據出現,瀏覽器可以使用XSLT文件把它轉換為可視化的輸出。應用程序可以使用兼容HTML的控件顯示這種信息。至于用戶,他們不管數據來自標準的幫助文件或另一個信息源。
最終,XML可能成為一種主要的數據存儲技術。有些廠商已經討論他們的XML產品了。你也可以找到一些XML存儲產品,例如微軟Office。簡單的說,你最終可能發現為了載入數據和顯示數據,需要在應用程序中包含分析能力。
生成XML文件
在你能更多地處理XML之前,你需要了解如何格式化XML文件,以及如果生成它。我假定你已經知道了如何格式化XML文件。列表2顯示了生成XML的一個簡單的方法。
列表2.使用.NET生成XML文件
System::Void btnGenerate_Click(System::Object * sender,
System::EventArgs * e)
{
XmlTextWriter* DataWrite; // 執行實際的數據寫入
// 建立數據寫入程序
DataWrite = new XmlTextWriter(txtFilename->Text,
System::Text::Encoding::UTF8);
// 寫入XML頭。當你把這個函數設置為true的時候,.NET建立獨立的文檔
DataWrite->WriteStartDocument(true);
DataWrite->WriteWhitespace("\r\n");
// 描述測試文件
DataWrite->WriteComment("This is a test document.");
DataWrite->WriteWhitespace("\r\n");
// 啟動文檔。你必須指定true來建立一個有根元素的新文檔。
// 包含根元素失敗將導致一個錯誤產生。
// 本示例包含了一個名字空間前綴、元素的本地名稱和于名字空間關聯的URL。
DataWrite->WriteStartElement("Data",
"MyData",
"http://www.mysite.com/");
DataWrite->WriteWhitespace("\r\n");
// 把數據寫入文檔
DataWrite->WriteElementString("DataString1", txtData->Text);
DataWrite->WriteWhitespace("\r\n");
// 用特定的屬性寫入相同的數據
DataWrite->WriteStartElement("DataString2");
DataWrite->WriteAttributeString("AnAttribute", "AttributeValue");
DataWrite->WriteString(txtData->Text);
DataWrite->WriteEndElement();
DataWrite->WriteWhitespace("\r\n");
// 終止起初的元素或文檔的根元素。
DataWrite->WriteEndElement();
// 終止文檔
DataWrite->WriteEndDocument();
// 關閉文檔。該調用包括把緩沖區的內容寫入磁盤的功能。
DataWrite->Close();
// 顯示文檔是完整的。
MessageBox::Show("File Generated",
"XML Generation Results",
MessageBoxButtons::OK,
MessageBoxIcon::Information);
}
在這個例子中,你建立XmlTextWriter對象--DataWrite的時候, XML寫入事務就開始了。你使用了特定的方法寫入XML文檔輸出。.NET框架組件要求你使用某些方法生成良好格式化的XML。例如,你必須使用WriteStartDocument()方法來定義文檔的開始,它是XML頭。當你使用WriteEndDocument()方法來關閉這種標志,使用Close()把文檔緩沖區的內容寫入磁盤,并執行實際的文件關閉的時候,寫入對話終止。
XML文檔需要根元素。第一個WriteStartElement()調用和相關的WriteEndElement()調用建立這種根元素。示例給出了根元素中的兩種類型的子元素。第一種演示了如何使用WriteElementString()方法寫入把沒有屬性的字符串。第二種演示了如何使用WriteAttributeString()方法給元素添加屬性。
示例也包含了少量可選的元素。有些開發者不關心輸出文件是如何出現的,但是我通常在文本編輯器中查看輸出。使用WriteWhitespace()方法添加一個回車符和制表符(如果希望的話)將使結果文件更容易在文本編輯器中閱讀。當然,類似Internet Explorer的應用程序和Visual Studio IDE不會關心空格的。
你也可能希望在記錄文件中包括注釋。你可以使用WriteComment()方法完成這種事務。圖1顯示了輸出在Internet Explorer中查看的時候看到的生成循環。
解析XML文件
如果以后你不能讀取示例應用程序中的XML輸出以提取它包含的所有信息,那么它就不夠好。有些開發者試圖把XML文件分析為實體,但是實際上用兩個步驟更容易實現這個過程。首先,打開文件并得到一個節點。其次,僅僅處理這個節點而不管剩余的節點。列表3演示了這個處理過程的第一部分:得到一個節點。
列表3.XML文件分析概觀
System::Void btnParse_Click(System::Object * sender,
System::EventArgs * e)
{
XmlTextReader* DataRead; // 載入數據以供讀取
StringBuilder* Output; // 分析后的輸出信息
// 打開文件以讀取頭
DataRead = new XmlTextReader(txtFilename->Text);
// 初始化輸出
Output = new StringBuilder();
// 繼續讀取頭節點直到完成
while (DataRead->Read())
{
// 得到每個節點的信息
Output->Append(ProcessEntry(DataRead));
Output->Append("\r\n");
}
// 顯示結果
MessageBox::Show(Output->ToString(),
"XML Parsing Results",
MessageBoxButtons::OK,
MessageBoxIcon::Information);
// 關閉文檔
DataRead->Close();
}
當代碼通過建立新的XmlTextReader打開文檔的時候這個過程就開始了。打開XmlTextReader的時候把文件的指針放在文件的開頭了。你必須執行一些其它的事務(例如使用上面顯示的Read()方法)來得到第一個節點。如果你試圖執行這個過程而沒有使用Read()或其它的可以接受的方法,應用程序會產生空(null)引用的錯誤。
示例通過調用ProcessEntry()方法(列表4所示)每次處理一個節點。它把節點的數據追加到StringBuilder對象(Output)。Read()方法一直返回true,直到測試程序處理了文件中的所有節點。這個時候,處理循環結束,示例調用Close()方法關閉文件。你需要確保執行了最后一步。
ProcessEntry()方法執行這個過程的第二步:從單個節點中得到數據(如列表4所示),這個方法檢索你需要處理的數據的通用信息。
列表4.XML文件分析細節信息
StringBuilder* ProcessEntry(XmlTextReader* Reader)
{
StringBuilder* DataOut; // 得到輸出
// 初始化輸出
DataOut = new StringBuilder();
// 檢測節點類型
switch (Reader->NodeType)
{
case XmlNodeType::Attribute:
DataOut->Append("Attribute");
break;
// ...處理其它類型...
case XmlNodeType::XmlDeclaration:
DataOut->Append("XML Declaration");
break;
default:
DataOut->Append("Type Unknown");
}
// 添加元素名稱
DataOut->Append("\t");
DataOut->Append(Reader->Name);
// 添加元素的值
if (Reader->HasValue)
{
DataOut->Append("\t");
DataOut->Append(Reader->Value);
}
// 添加屬性
if (Reader->HasAttributes)
for (Int32 Counter = 0;
Counter < Reader->AttributeCount;
Counter++)
{
Reader->MoveToAttribute(Counter);
DataOut->Append("\r\n\t");
DataOut->Append(Counter);
DataOut->Append("\t");
DataOut->Append(Reader->Name);
DataOut->Append("\t");
DataOut->Append(Reader->Value);
}
// 返回結果
return DataOut;
}
ProcessEntry()方法從通過使用NodeType屬性檢測節點的類型開始。示例輸出一個標識節點類型的字符串,但是作為產品的應用程序通常使用節點類型定義處理操作或檢測它是否需要執行處理過程。在這種情況下,示例建立DataOut StringBuilder對象來保持節點類型信息。
每個節點都有名稱,因此下面的文本把Name屬性值添加到DataOut。名稱值可以由你指定(例如圖1中的DataString1),或者由.NET框架組件指定默認值。例如,注釋沒有準確的名稱,因此.NET框架組件賦予它的名字是Comment。
大多數節點也有值。但是,你必須使用HasValue屬性檢驗當前節點是否有值。如果示例檢測到了當前節點的值,它就把節點的Value屬性添加到DataOut。
有些節點也有屬性。但是,在使用HasAttributes屬性檢查他們之前,你必須檢查他們的屬性。AttributeCount屬性表明了某個節點有多少個屬性(可以多于一個)。這是一個零值為基礎的值。示例使用MoveToAttribute()方法把當前屬性載入讀取程序。接著代碼就可以正常使用Name和Value屬性了。
請注意:你不必執行詳細的屬性處理。如果你需要的是屬性值,使用方Reader->GetAttribute()法就可以了,該方法僅僅返回所有屬性的值并能節省少量處理步驟。但是,一般情況下你需要同時知道屬性的名稱和值,因此列表4中的處理技術比你現在使用的其它技術更加通用。圖2顯示了這個程序的典型輸出信息。
注意:圖2中顯示了少量你可能沒有估計到的信息。例如,XML頭中的信息(類似版本號),對.NET框架組件來說它是作為屬性出現的。示例代碼也包含了列表1中的清單文件的副本。你可以在Filename字段中輸入這個文件的路徑和名稱。應用程序分析這個文件與它分析自己生成的XML文件的容易程度是一樣的。實際上,這個應用程序可以處理任何良好格式化的XML文件。
總結
現在你已經知道了.NET中使用XML文件是多么容易了。讀取和寫入XML文件并不比處理一個典型的文本文件復雜。此外,你可能發現了少量以前沒有考慮過的XML的新的用法。隨著微軟把對XML的支持添加到更多的產品中,你可以確性在.NET中分析XML的簡便性將使你的開發工作更加容易。