修改大型 XML 文件的有效方法
這篇論文說明了修改 XML 文檔的一些可供選擇的方法,這些方法不涉及將文檔加載到 XmlDocument 實例中的內容。
使用 XML 包含方法
建議的第一種方法對于向 XML 日志文件追加值最為有用。開發人員面臨的常見問題是需要一種能夠將新條目簡單地追加到日志文件中而不用加載文檔的方法。因為 XML 具有良好結構規則,所以使用傳統方式(這種方法會因為日志文件格式不正確而結束日志文件)來向 XML 日志文件追加條目通常是非常困難的。
要說明的第一種方法是針對這樣的情形,即目的是能夠將條目快速地追加到 XML 文檔中。這種方法包括創建兩個文件。第一個文件是格式正確的 XML 文件,第二個是 XML 片段。格式正確的 XML 文件包括 XML 片段,XML 片段使用 DTD 中聲明的 external entity 或者使用 xi:include element 。使用包含文件,通過在進行處理過程中簡單地追加到 XML 文件,可以有效地更新文件包含 XML 片段的方法。包含文件和被包含文件的示例如下所示:
Logfile.xml:
<?xml version="1.0"?>
<!DOCTYPE logfile [
<!ENTITY events
SYSTEM "logfile-entries.txt">
]>
<logfile>
&events;
</logfile>
Logfile-events.txt:
<event>
<ip>127.0.0.1</ip>
<http_method>GET</http_method>
<file>index.html</file>
<date>2004-04-01T17:35:20.0656808-08:00</date>
</event>
<event>
<ip>127.0.0.1</ip>
<http_method>GET</http_method>
<file>stylesheet.css</file>
<date>2004-04-01T17:35:23.0656120-08:00</date>
<referrer>http://www.example.com/index.html</referrer>
</event>
<event>
<ip>127.0.0.1</ip>
<http_method>GET</http_method>
<file>logo.gif</file>
<date>2004-04-01T17:35:25.238220-08:00</date>
<referrer>http://www.example.com/index.html</referrer>
</event>
logfile-entries.txt 文件包括一個 XML 片段,并且可以使用典型的文件 IO 方法有效地進行更新。下面的代碼說明了如何通過將條目追加到文本文件的結尾來將它添加到 XML 日志文件中。
using?System.IO;
using?System.Xml;?
public?class?Test{?
public?static?void?Main(string[]?args){
StreamWriter?sw?=?File.AppendText("logfile-entries.txt");
XmlTextWriter?xtw?=?new?XmlTextWriter(sw);?
xtw.WriteStartElement("event");?
xtw.WriteElementString("ip",?"192.168.0.1");
xtw.WriteElementString("http_method",?"POST");
xtw.WriteElementString("file",?"comments.aspx");
xtw.WriteElementString("date",?"1999-05-05T19:25:13.238220-08:00");?
xtw.Close();
}
}
一旦條目被追加到文本文件中,使用傳統的 XML 處理方法,就可以處理 XML 日志文件中的條目。下面的代碼使用 XPath 遍歷了 logfile.xml 中的日志事件,同時列出了它們被訪問時的文件以及被訪問的文件。
using?System.Xml;?
public?class?Test2{
public?static?void?Main(string[]?args){
XmlValidatingReader?vr?=?
new?XmlValidatingReader(new?XmlTextReader("logfile.xml"));
vr.ValidationType?=?ValidationType.None;?
vr.EntityHandling?=?EntityHandling.ExpandEntities;?
XmlDocument?doc?=?new?XmlDocument();?
doc.Load(vr);?
foreach(XmlElement?element?in?doc.SelectNodes("//event")){
string?file?=?element.ChildNodes[2].InnerText;?
string?date?=?element.ChildNodes[3].InnerText;?
Console.WriteLine("{0}?accessed?at?{1}",?file,?date);
}?
}
}?
上面的代碼導致了下面的輸出:
index.html accessed at 2004-04-01T17:35:20.0656808-08:00
stylesheet.css accessed at 2004-04-01T17:35:23.0656120-08:00
logo.gif accessed at 2004-04-01T17:35:25.238220-08:00
comments.aspx accessed at 1999-05-05T19:25:13.238220-08:00
更改 XmlReader 為 XmlWriter
在某些情況下,除了只將元素追加到根元素中外,還需要對 XML 文件執行更復雜的操作。例如,要篩選日志文件中的每一個條目,而這些條目在存檔到日志文件前不符合某些特殊標準。要完成此任務的一種方法是將 XML 文件加載到 XmlDocument 中,然后通過 XPath 選擇感興趣的事件。但是,這樣做涉及將整個文檔加載到內存中,如果文檔太大,則這種做法會受到限制。另一種選擇方法為了這種任務會涉及使用 XSLT,但是由于整個 XML 文檔需要保存到內存中,這種方法會和 XmlDocument 方法一樣遇到相同的問題。另外,由于開發人員不熟悉 XSLT,了解如何正確使用模板匹配時會遇到較大的困難。
要解決如何處理大型 XML 文檔問題的一種方法是使用 XmlReader 讀取 XML,讀取的同時使用 XmlWriter 將其寫出。使用這種方法,整個文檔不會同時存入內存中,對 XML 可以進行更精確的更改而不只是追加元素。下面的代碼示例讀取前面部分的 XML 文檔,篩選出所有 ip 元素的值為 "127.0.0.1" 的事件后將其保存為存檔文件。
using?System.Xml;?
using?System.IO;
using?System.Text;
public?class?Test2{
static?string?ipKey;
static?string?httpMethodKey;
static?string?fileKey;?
static?string?dateKey;
static?string?referrerKey;?
public?static?void?WriteAttributes(XmlReader?reader,?XmlWriter?writer){
if(reader.MoveToFirstAttribute()){
do{
writer.WriteAttributeString(reader.Prefix,?
reader.LocalName,?
reader.NamespaceURI,
reader.Value);?
}while(reader.MoveToNextAttribute());
reader.MoveToElement();?
}
}
public?static?void?WriteEvent(XmlWriter?writer,?string?ip,
string?httpMethod,?string?file,
string?date,?string?referrer){
writer.WriteStartElement("event");?
writer.WriteElementString("ip",?ip);
writer.WriteElementString("http_method",?httpMethod);
writer.WriteElementString("file",?file);
writer.WriteElementString("date",?date);?
if(referrer?!=?null)?writer.WriteElementString("referrer",?referrer);
writer.WriteEndElement();?
}?
public?static?void?ReadEvent(XmlReader?reader,?out?string?ip,
out?string?httpMethod,?out?string?file,
out?string?date,?out?string?referrer){
ip?=?httpMethod?=?file?=?date?=?referrer?=?null;?
while(?reader.Read()?&&?reader.NodeType?!=?XmlNodeType.EndElement){?
if?(reader.NodeType?==?XmlNodeType.Element)?{
if(reader.Name?==?ipKey){?
ip?=?reader.ReadString();?
}else?if(reader.Name?==?httpMethodKey){?
httpMethod?=?reader.ReadString();
}else?if(reader.Name?==?fileKey){?
file?=?reader.ReadString();
}else?if(reader.Name?==?dateKey){?
date?=?reader.ReadString();
//?reader.Read();?//?使用結尾標記
}else?if(reader.Name?==?referrerKey){?
referrer?=?reader.ReadString();
}
}//if?
}//while?
}
public?static?void?Main(string[]?args){
string?ip,?httpMethod,?file,?date,?referrer;?
//使用用于進行比較的字符串設置?XmlNameTable
XmlNameTable?xnt?=?new?NameTable();?
ipKey?=?xnt.Add("ip");?
httpMethodKey?=?xnt.Add("http_method");?
fileKey?=?xnt.Add("file");
dateKey?=?xnt.Add("date");
referrerKey?=?xnt.Add("referrer");
//使用上面的?XmlNameTable?加載?XmlTextReader?
XmlTextReader?xr?=?new?XmlTextReader("logfile.xml",?xnt);
xr.WhitespaceHandling?=?WhitespaceHandling.Significant;
XmlValidatingReader?vr?=?new?XmlValidatingReader(xr);
vr.ValidationType?=?ValidationType.None;
vr.EntityHandling?=?EntityHandling.ExpandEntities;?
StreamWriter?sw?=?
new?StreamWriter?("logfile-archive.xml",?false,?Encoding.UTF8?);?
XmlWriter?xw?=?new?XmlTextWriter?(sw);?
vr.MoveToContent();?//?移到文檔元素?
xw.WriteStartElement(vr.Prefix,?vr.LocalName,?vr.NamespaceURI);
WriteAttributes(vr,?xw);?
vr.Read();?//?移到文檔元素的第一個?<event>?子元素
//?寫出不是?127.0.0.1(本地主機)中的事件
do
{
ReadEvent(vr,?out?ip,?out?httpMethod,?
out?file,?out?date,?out?referrer);
if(!ip.Equals("127.0.0.1")){
WriteEvent(xw,ip,?httpMethod,?file,?date,?referrer);?
}
vr.Read();?//移到下一個?<event>?元素或?<logfile>?的結尾標記
}?while(vr.NodeType?==?XmlNodeType.Element);
Console.WriteLine("Done");
vr.Close();
xw.Close();
}
}
上面的代碼示例在寫入到 logfile-archive.xml 文件中時會導致下面的輸出:
<logfile>
<event>
<ip>192.168.0.1</ip>
<http_method>POST</http_method>
<file>comments.aspx</file>
<date>1999-05-05T19:25:13.238220-08:00</date>
</event>
</logfile>
除了使用 XmlReader 到 XmlWriter 的鏈之外,上面代碼的另一個有趣方面是,使用 ReadEvent() 方法檢查元素標記名稱時使用 NameTable 提高了文本比較的性能。在 XmlReader 中使用這種方法檢查元素的標記名稱的優點在如下的 MSDN 文檔主題中進行了概述:Object Comparison Using XmlNameTable with XmlReader(英文)。
轉載于:https://www.cnblogs.com/Dragon-China/archive/2007/01/10/616900.html
總結
以上是生活随笔為你收集整理的修改大型 XML 文件的有效方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不要太相信眼睛
- 下一篇: Win API记录点滴