关闭

『IT视界』 [软件]用.NET的XML类来读写XML文件

658人阅读 评论(0) 收藏 举报
IT视界』 [软件]用.NET的XML类来读写XML文件

  作者: 参天古柏 提交日期:2006-5-17 08:18:00  
.NET框架为XML所提供的拉方法(pull method)简化了对XML文家的读写过程——这要归功于XmlReaderXmlWriter导出类。让我们看看XmlReader 和XmlWriter类是如何处理XML文档的。(如果你想对拉方法和.NET的XML类有个高层次的认识,请参阅《带你遨游.NET的XML世界》)我已经写好了一个工作在控制台模式下的应用程序,它是一个很不错的例子,而且特别贴近实际情况。用户可以用这个名位XMLDemoCSharp的项目(你可以在这儿下载源代码)来把一个书单当作XML文档来维护。书的目录很快就会成为规范的XML例子,从XML书目中找到你需要的东西总是比埋头于标签要简单些。你可以免费使用清单A中的例子文档,不过你可不要说我什么功能也没有实现,OK?
  
  XMLDemoCSharp中的大部分代码是用来处理用户界面的,如果你考虑到我在这个项目中为了简化而使用了控制台模式,就会发现这很有讽刺意味。你可以充分忽略这其中的大多数代码,而把精力集中在Book类上,Book类实现把书整合到书目中的功能Book类提供两个静态方法来分别提取和保存书目,即LoadBooks和SaveBooks。
  
  用XmlTextReader来读XML文档
  XMLDemoCSharp首先通过调用LoadBooks方法来载入书目,代码如清单B中所示。LoadBooks使用System.Xml.XmlTextReader实(concrete)类来一个元素接着一个元素的读取XML文档,并创建一个System.Collections.ArrayList来表示书目中的书。XmlTextReader是一个前向(只能前向)的语法分析器(parser),其工作方式与SAX相似,它按照元素在文档出现的顺序从头到尾检索元素。尽管XmlTextReader并不支持有效性验证(validation),但是它的速度很快并且并不很消耗资源。同样,如果速度是你的优化目标又或者你不需要像XML schema或者DTD那样要求有效性验证(validation),XmlTextReader是你理想的选择。
  
  用阅读器来读取(up)流
  
  XmlTextReader可以控制阅读文件过程的细节(被读文件的URL是你在XmlTextReader的构造函数中指定的),它也可以通过一个System.IO.Stream对象来读XML文档。流是允许你访问灵活的输入和输出设备,它不仅可以是文件,也可以是内存或者网络数据(network data)。如果你现在不习惯.NET的基于流的输入输出操作,我建议你尽快熟悉它。
  调试XmlTextReader应用程序
  
  在用XmlTextReader读取文档之前,你需要了解下面这些基本概念,否则你很容易糊涂起来:
  
  XmlTextReader就像DOM那样,它用一系列节点来表示XML文档,一个节点可能对应文档中的某个元素,也可能不对应。当一个元素包含其它元素时(如本例中的<catalog>元素),每个标签(tag)用一个节点来表示。所以<catalog>实际上是两个节点:一个表示开始标签,即<catalog>,另一个表示结束标签,即</catalog>。
  当节点包含数据时,元素和数据将会是三个分开的节点。
  嵌套元素实际上读了两次:一次是XmlTextReader阅读器到达该元素的开始标签节点时,第二次是该元素的结束标签出现在流中时(这是所有的嵌套元素都被处理完了)。
  以单词Read开头的方法会把XmlTextReader的节点指针移到流中的下一个节点上。一旦你把节点指针移到下一个节点上,你就不能再移回到原先的节点上——除非你重新开始处理该文档。
  载入书目
  
  在LoadBooks中,我首先调用XmlTextReader.ReadStartElement方法来把根节点<catalog>移到文档中的第一个元素<book>上,XmlTextReader.ReadStartElement方法用来把阅读器(reader)移到流中下一个开始标签上。然后我设置了一个while循环,这个循环将一直运行下去,直到<catalog>元素再次变成当前值(这通过在每次循环时检测LocalName属性来判断)。当阅读器遇到表示</catalog>结束标签的节点时,我们就已经分析完整个文档了。
  
  处理某一本书的第一个步骤就是获得它的id属性,可以通过GetAttribute方法获得id。然后,我调用Read来移到<book>的第一个嵌套元素上。接着用另一个while循环来处理每一个<book>子元素,整个循环直到碰到</book>结束标记(表示已经处理完一本书了)为止。每一本书按照它在文档中出现的顺序依次这样处理,我通过检查每个元素的LocalName属性来判断如何处理接收到的数据。注意我需要对每个数据元素调用了三次读方法:开始标记节点的Read,数据节点的ReadString,以及对结束标记节点的Read。
  
  调试XmlTextReader应用程序
  
  在完成XMLDemoCSharp的过程中,我理所当然的需要跟踪并检查出现的bug。在这个过程中,我发现调试本应用程序时最大的挑战就是很难判断阅读器处于文档中的什么地方:由于某些节点没有名字,你不能总是通过检查LocalName属性来判断。我发现当抛出一个例外时,XmlTextReader的LineNumber和LinePosition属性可以帮助判断阅读器在文档中的位置。通过检查这两个属性并时刻注意你正在分析的文档,一般都可以判断进行到什么地方了。
  
  用XmlTextWriter写XML文档
  
  XmlTextWriter来写XML文档
  
  
  
  当看完书目后,用户可能还想向书目中添加若干本新书,用户可以选择把书目存回到磁盘中的XML文件中。XMLDemoCSharp在SaveBooks方法中实现了这个功能(程序清单C),该方法使用了System.Xml.XmlTextWriter类。XmlTextWriter类是XmlWriter抽象类的一个简单继承类,它提供了一种创建XML文档和文档片断的可靠(fast)途径。XmlTextWriter不支持有效性验证(validation),但是它提供了创建绝大多数XML结构的方法。
  
  和XmlTextReader一样,XmlTextWriter维护了一个内部节点指针,每一个节点等价于文档中一个标记或者一段数据。为了把XML写到文档中,你可以调用几个以单词Write开头的方法中的一种。一种方法对应于向XML文档流中写一种XML元素。例如WriteElementStart方法创建元素的开始标记,WriteElementEnd方法创建结束标记,而WriteElementString方法每调用一次就全部创建开始标记、数据和结束标记。
  
  保存书目
  
  保存书目比载入书目要简单的多。首先,我把一个Stream对象传递给SaveBooks创建创建一个新的XmlTextWriter实例。然后,我用WriteStartDocument方法向文档中写入XML版本申明。当这些工作完成之后,我就可以开始向文档写元素了。
  
  由于<catalog>不包含数据而包含嵌套元素,我用WriteStartElement创建它的开始标记。在for…each循环中,为书目中的每一本书创建一个<book>元素。先用WriteStartElement写一个开始标记;然后用WriteElementString创建六个数据元素来代表书目中的书;最后通过调用WriteEndElement创建结束标记来关闭<book>元素。
  
  一旦所有书的信息都写到文档中,根元素<catalog>就用WriteEndElement来关闭。注意WriteEndElement调用时并没有指定关闭的元素名,这是由于XmlTextWriter跟踪内部最后一个开始的元素,当你调用WriteEndElement时它会自动写入适当的结束标记。最后一件需要我们做的事就是刷新(flush)并关闭书写器(writer)的输出流,这样文档就被保存下来了。
  
  正如你所见到的那样,用.NET的拉方法类去读写XML文档比用其它主要的XML语法分析API(如SAX和DOM)要简单的多。XmlTextReader和XmlTextWriter类简单、可靠、易于使用;如果你只需要简单的XML功能,那么欠缺有效性验证(validation)也不会产生问题。 
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:145099次
    • 积分:2015
    • 等级:
    • 排名:第19145名
    • 原创:45篇
    • 转载:64篇
    • 译文:2篇
    • 评论:27条
    文章分类
    最新评论
    友情链接