随着 XML 成为大型信息源的常用表示格式,开发人员编辑大型 XML 文件时开始遇到问题。对于处理大型日志文件以及经常需要为这些文件追加信息的应用程序,尤其如此。编辑 XML 文件最直接的方法是,将其加载到 XmlDocument 中,在内存中修改文档,然后将其保存回磁盘。但是,这样做意味着要将整个 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;
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;
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;
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 文件的有效方法相关推荐

  1. xml文件上传服务器读取不了,使用Post从服务器读取大型xml文件时内存不足

    我正在使用以下代码从服务器获取xml文件,并且由于重型和大型xml文件,它崩溃并显示内存不足问题. public class Connect { static BufferedReader in=nu ...

  2. python写xml文件 数据量特别大_python中大型xml文件的并行处理

    我有几个正在解析的大型xml文件(提取一些数据子集并写入文件),但是每个文件都有很多文件和大量记录,所以我尝试并行化.在 首先,我有一个生成器从文件中提取记录(这很好):def reader(file ...

  3. java文件和xml文件_用Java分割大型XML文件

    java文件和xml文件 上周,我被要求用Java编写一些东西,该东西能够将一个30GB的XML文件拆分为可配置文件大小的较小部分. 文件的使用者将是一个中间件应用程序,该应用程序在XML的大尺寸方面 ...

  4. 用Java分割大型XML文件

    上周,我被要求用Java编写一些东西,该东西能够将单个30GB XML文件拆分为可配置文件大小的较小部分. 该文件的使用者将是一个中间件应用程序,该应用程序存在XML较大的问题. 在后台,它使用某种D ...

  5. tomcat修改tomcat-users.xml文件,服务器重启后又自动还原

    tomcat配置用户管理权限,修改tomcat-users.xml文件 在tomcat目录中找到/conf/tomcat-users.xml,修改 <tomcat-users>     & ...

  6. 简单的VC 操作XML 文件的的方法

    首先建立一个XML文件,我的机器软件configuration如下: Windows xp professional sp2 IE 6.0( 无关紧要) VS 2003 --------------- ...

  7. 查看target/classes/.../dao/文件夹下,发现只有mapper的class文件,而没有xml文件 的解决方法。

    控制台报错:Invalid bound statement (not found): cn.e3mall.mapper.TbItemMapper.selectByExample Console界面的错 ...

  8. Eclipse关闭XML文件验证的方法

    XML的编写是否符合规范,可以通过XML Schema或DTD进行验证,但有时候电脑本来就很卡,而且XML的某些错误并未导致程序无法运行的情况下,暂时关闭XML的验证也算不错的选择. 如web.xml ...

  9. python读取xml文件有哪些方法_深入解读Python 解析xml的几种方式

    一,概述 在XML解析方面,Python贯彻了自己开箱即用batteries included的原则, 在自带的标准库中,python提供了大量可以用于处理XML语言的包和工具 二,正文 1,什么是X ...

最新文章

  1. AprilTag中的apriltag.h文件
  2. 美媒看衰马斯克超级高铁:纽约到华盛顿挖隧道要挖100年
  3. 西伯利亚(Siberia)冷空气
  4. 特征工程tf-idf_特征工程-保留和删除的内容
  5. 论文浅尝 | 问题多样性对于问答的帮助
  6. mysql如何计算qps_如何计算MySQL中的QPS及TPS指标
  7. 1092 回文字符串(51nod)
  8. 电脑不会当局者迷——评人机围棋大战
  9. Pycharm安装中文语言插件
  10. com词根词缀_【单词杂谈】推荐几个学习英语词根词缀的网站,建议收藏!
  11. 数据库课程设计:图书借阅管理系统(控制台交互)
  12. ubuntu安装ipython3_ubuntu下ipython的安装
  13. https://blog.csdn.net/qq_43412289
  14. SpringBoot学期总结
  15. Problem G: 切煎饼
  16. 相忘于江湖——记另一位朋友
  17. vue3.0 + tsx 构建el-button
  18. Windows 10文件夹中的一些高级搜索技巧
  19. MySQL数据库的官网下载、安装及卸载(2018年最新)
  20. 计算机人事管理参考文献,计算机人事管理系统毕业论文设计.doc

热门文章

  1. 实验五 操作系统之存储管理
  2. Activity之间切换 以及传值
  3. WIN7 64位系统注册银行支付组件
  4. table选项卡从A页面点击进入B页面指定版块
  5. IOS 4.0 以上版本 home键退出 后台执行代码
  6. Android 3D开发,OpenGL ES 的使用(一)
  7. Cannot resolve corresponding JNI function
  8. android LinkedList的基本用法
  9. so使用原则(要么不支持,要么全部支持) 固定的运行平台 指定目录:System.load(/data/data/package-name/mydir/libmath.so);
  10. Linux 解压命令