`
zjf-2004
  • 浏览: 10367 次
  • 性别: Icon_minigender_1
  • 来自: 张家港
最近访客 更多访客>>
社区版块
存档分类
最新评论

【译】修改大XML文件的有效方法

 
阅读更多

【译】修改大XML文件的有效方法
By Dare Obasanjo
Microsoft Corporation
April 2004
by 烈火青春
2010-07-18
概述:Dare Obasanjo展示了两种方法来更新或操作大XML文件,如日志文件、数据库的dump文件。
介绍:随着XML越来越流行于作为储存大量信息的带格式文件,开发者已经意识到了编辑大XML文件的问题了。对那些记录着日志文件并需要不断追加信息到这些文件中的应用尤为突出。大多数简单的方法来编辑XML文件就是直接用XmlDocument来加载,然后在内存中编辑document对象,然后再保存回到磁盘中。然而这样做意味着整个XML都加载到了内存中,这可能会让应用程序占在大量内存而变得不可行。
本文本展示了一些不需要用XmlDocument加载XML文件来来修改XML文件的方法。
使用XML包含的方法(Using XML Inclusion Techniques)
将要介绍的第一种方法非常适合于追加数据到XML日志文件中。开发者常面对的一个问题是需要简单地追加一些新实体到一个日志文件,而不是先加载整个document。因为XML有着规则的结构,所以用传统方式将一个实体追加到文件的结尾是基本不可行的。
这个方法将会展示的是能够快速在XML document中插入一个对象。该方法需要产生两个文件,第一个是XML结构文件,而第二个文件是一个XML数据片段。XML结构文件包含包着XML片段的定义,采用外部定义实体的方式DTD或使用xi:include element。采用这种包含XML片段的文件,就可以简单地直接追加文件到XML中。以下是一个采用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-entires.txt文件包含着XML片段数据,可以有效地使用典型的文件IO操作函数。下面的代码展示着一个实体是如何追加到这个XML日志文件中:
using System;
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();
}
}
一旦实体追加到这个txt文件中后,通过传统地XML处理方式就可以读到这个数据。下面的代码采用Xpath来遍历logfile.xml中的所有events,列表展示出所有访问过的页面信息。
using System;
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
Chaining an XmlReader to an XmlWriter
某些情况下可能需要对XML文件进行更细致的操作此外还有仅需要在根结点插入一个元素的操作。例如,可能在日志文件存档时需要将不满足某些规则的元素筛选出来。一般的做法是加载XMLXmlDocument中,然后将通过Xpath将这些规则下的元素选择出来。然后,这样做需要将整个XML加到内存中,如果文档太大程序可能会崩溃。另一个想到是利用XSLT来解决,但同样这样也会面临XmlDocument加载所有到内存中的问题。当然,开发人员可能还不熟悉XSLT的话,要理解如何用模板匹配属性跨度就有点大了。
一个解决这类问题的方法就是如何用XmlReader读取XML文件,加以处理处理大XML文件,然后再用XmlWriter写出已经读出的内容。这种方法不会一次性将整个文件加载到内存中,在简单地追加写文件前可以做各种操作。下面的代码就展示着,从前面读到XML文件,然后保存XML文件前,排除IP=127.0.0.1”的元素数据。(代码可以粘帖至控制台程序运行来查看结果!)
using System;
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(); // consume end tag
}else if(reader.Name == referrerKey){
referrer = reader.ReadString();
}
}//if
}//while
}
public static void Main(string[] args){
string ip, httpMethod, file, date, referrer;
//setup XmlNameTable with strings we'll be using for comparisons
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");
//load XmlTextReader using XmlNameTable above
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(); // Move to document element
xw.WriteStartElement(vr.Prefix, vr.LocalName, vr.NamespaceURI);
WriteAttributes(vr, xw);
vr.Read(); // Move to first <event> child of document element
// Write out each event that isn't from 127.0.0.1 (localhost)
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(); //move to next <event> element or end tag of <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外,还使用了NameTable来提升从ReadEvent()方法中取取元素的名称比较的性能。这种使用法在XMLReader中的好处已经在MSDN中的Object Comparison Using XmlNameTable with XmlReader一文中指出。
引原文地址:http://msdn.microsoft.com/en-us/library/aa302289.aspx
分享到:
评论

相关推荐

    C#XML入门经典 C#编程人员必备的XML技能.part2

    C# XML入门经典——C#编程人员必备的XML技能 作者:[美]Stewart Fraser, Steven 著,毛尧飞,崔伟 译 出版社:清华大学出版社 出版时间:2003年11月 第1章 在C#中使用XML的原因 &lt;br&gt;1.1 使用XML的原因...

    java 面试题 总结

    当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。 17、abstract class和interface有什么区别? 声明方法...

    超级有影响力霸气的Java面试题大全文档

    当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。 20、abstract class和interface有什么区别? ...

    asp.net知识库

    使用.ashx文件处理IHttpHandler实现发送文本及二进制数据的方法 制作一个简单的多页Tab功能 一完美的关于请求的目录不存在而需要url重写的解决方案! 在C#中实现MSN消息框的功能 XmlHttp实现无刷新三联动ListBox 鼠标...

    C#微软培训资料

    8.3 条 件 编 译.90 8.4 异常处理语句 .95 8.5 小 结 .100 第三部分 面向对象的 C#.101 第九章 面向对象的程序设计 .101 9.1 面向对象的基本概念.101 9.2 对象的模型技术 .103 9.3 面向对象的分析 .105...

    中文版Excel.2007高级VBA编程宝典.part1

    冯飞,焦瑜净 译 出版社:清华大学出版社 出版日期:2009-2-1 ISBN:9787302194675 字数:1294000 页码:872 编辑推荐 -------------------------------------------------------------------------------- “电子...

    antlr4权威指南

    随后,你会学到在语法中嵌入动作的方法——在某些场景下,这样做比建立树并遍历之更简单,也更有效率。此外,你还将学会使用语义判定(semantic predicate)来修改语法分析器的行为,以便解决一些充满挑战的识别难题...

Global site tag (gtag.js) - Google Analytics