新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论DOM, SAX, XPath等。
    [返回] 中文XML论坛 - 专业的XML技术讨论区XML.ORG.CN讨论区 - XML技术『 DOM/SAX/XPath 』 → [转帖]修改大型 XML 文件的有效方法 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 3668 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: [转帖]修改大型 XML 文件的有效方法 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     Qr 帅哥哟,离线,有人找我吗?
      
      
      威望:9
      等级:博士二年级(版主)
      文章:4392
      积分:29981
      门派:XML.ORG.CN
      注册:2004/5/15

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给Qr发送一个短消息 把Qr加入好友 查看Qr的个人资料 搜索Qr在『 DOM/SAX/XPath 』的所有贴子 访问Qr的主页 引用回复这个贴子 回复这个贴子 查看Qr的博客楼主
    发贴心情 [转帖]修改大型 XML 文件的有效方法

    修改大型 XML 文件的有效方法
    转自:http://www.microsoft.com/china/MSDN/library/data/xml/largexml.mspx?mfr=true
    发布日期: 8/12/2004 | 更新日期: 8/12/2004
    Dare Obasanjo

    Microsoft Corporation

    摘要:Dare Obasanjo 说明了有效更新或修改大型 XML 文件(例如日志文件和数据库转储)的两种方法。

    本页内容
    引言
    使用 XML 包含方法
    更改 XmlReader 为 XmlWriter  
    致谢

    引言
    随着 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(英文)。

    返回页首
    致谢
    感谢 Martin Gudgin 鼓励我写这篇论文,他建议将 XmlReaderto 链接到 XmlWriteras 作为对有关编辑大型 XML 日志文件问题的解答。

    &copy; 2004 Microsoft Corporation 版权所有。保留所有权利。使用规定。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    没人帮忙,那就靠自己,自己才是最好的老师!本人拒绝回答通过站内短消息提出的问题!

    blog:http://Qr.blogger.org.cn

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/1/22 11:30:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 DOM/SAX/XPath 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/3 2:34:39

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    77.148ms