正 文

修改大型 XML 文件的有效方法


www.7dspace.com  更新日期:2005-10-4 9:42:37  七度空间


更改 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(英文)。

2页,页码:[1] [2] 

上一篇:通过 XML 发布新闻
下一篇:SQL Server 本机 Web 服务的使用方案
作者:Dare Obasanjo  来源:Microsoft ( 责任编辑:7dspace )
收藏此页】【打印】【关闭
站 内 搜 索
 

热 点 导 读
特 别 推 荐