xmlreader类
xml阅读器支持一个编程接口,接口用于连接xml文档,“推出”你要的数据。如果你更深入去了解阅读器,你会发现阅读器工作原理类似于我们的桌面应用程序从数据库中取出数据的原理。数据库服务返回一个游标对象,它包含所有查询结果集,并返回指向目标数据集的开始地址的引用。xml阅读器的客户端收到一个指向阅读器实例的引用。该实例提取底层的数据流并把取出的数据呈现为一棵xml树。阅读器类提供只读、向前的游标,你可以用阅读器类提供的方法滚动游标遍历结果集中的每一条数据。
从阅读器中看xml文档不是一个标签文本文件,而是一个序列化的节点集合。它是.net framework中的一种特殊的游标模式;在.net framework中,你找不到其它的任何一个类似的api函数。
阅读器和xmldom分析器有几点不同的地方。xml阅读器是只进的,它没有父、子、祖宗、兄弟节点的概念,而且是只读的。在.net framework中,读写xml文档是分为两种完全不同的功能,分别由xmlreader和xmlwriter类来完成。要编辑xml文档,你可以用xmldom分析器,或者你自己设计一个类来实现这两种功能。让我们开始分析阅读器的程序功能。
xmlreader是一个抽象类,你可以继承并扩展它的功能。用户程序一般都基于下面的三种类:xmltextreader、xmlvalidatingreader或者 xmlnodereader类。所有的这些类都有如图一的属性和图二的方法。要注意的是,某些属性的值实际上依赖于实际的某个阅读器类,不同的类与基类可能不同。因此,在图一中每个属性的说明都是以基类为准的。例如,canresolveentity属性在xmlvalidatingreader类中只返回true;而在其它的阅读器类中它却可以设为false。同样的,在图二中的某些方法的实际返回值对不同的类可能不同。例如,如果节点类型不是元素节点(element node),所有包含atrributes的方法的返回值类型都是void。
xmltextreader类用只进,只读的方式快速访问xml数据流。阅读器先验证xml文档是否是格式良好的,如果不是则抛出一个异常。xmltextreader 检查 dtd 的格式是否良好,但不使用 dtd 对文档进行验证。xmltextreader通过xml文档的文件名,或它的url,或者从文件流中载入xml文档,然后快速的处理xml文档数据。如果你需要对文档的数据进行验证,你可以用xmlvalidatingreader类。
可以用多种方法创建xmltextreader类的实例,从硬盘中加载文件,或从url地址中加载,流(streams)中加载,还有就是从文本中读入xml文档数据:
xmltextreader reader = new xmltextreader(file);
注意,所有xmltextreader类的公共(public)构造函数都要求你指定数据源,数据源可以是stream、文件或者其它。xmltextreader默认的构造函数是受保护的(protected),所以不能直接使用。像.net framework中所有的阅读器类一样(如sqldatareader类),一旦阅读器对象连接并打开,你就可以用read方法去访问数据了。开始的时候只能用read方法把指针移到第一个元素;然后我们可以用read方法或其它方法(如skip, movetocontent和readinnerxml)移动指针到下一个节点元素。要处理整个xml文档的内容,可以根据read方法的返回值用一个循环遍历文档内容,因为read方法返回一个布尔值,当读到文档的尾节点时,read方法返回false,否则它返回true。
figure 3 outputting an xml document node layout
string getxmlfilenodelayout(string file)
{
/ 创建一个xmltextreader类使它指向目标xml文档
xmltextreader reader = new xmltextreader(file);
/ 循环取出节点的文本并放入到stringwriter对象实例中
stringwriter writer = new stringwriter();
string tabprefix = "";
while (reader.read())
{
/ 写开始标志,如果节点类型为元素
if (reader.nodetype == xmlnodetype.element)
{
/根据元素所处节点的深度,加入reader.depth个tab符,然后把元素名写入到<>中。
tabprefix = new string('\t', reader.depth);
writer.writeline("{0}<{1}>", tabprefix, reader.name);
}
else
{
/写结束标志,如果节点类型为元素
if (reader.nodetype == xmlnodetype.endelement)
{
tabprefix = new string('\t', reader.depth);
writer.writeline("{0}{1}>", tabprefix, reader.name);
}
}
}
/ 输出到屏幕
string buf = writer.tostring();
writer.close();
/ 关闭流
reader.close();
return buf;
}
图三演示了一个简单的用于输出一个给定的xml文档的节点元素的函数。该函数先打开一个xml文档,然后用循环处理xml文档中所有的内容。每次调用read方法,阅读器的指针都会向下移一个节点。大部分情况下,用read方法可以处理的元素节点,但有时候,当你从一个节点移动到下一个节点时,可能是在两个不同类型的节点间移动。但是read方法不能在属性节点之间移动。阅读器的movetocontent方法可以让指针从头部节点位置跳到第一个内容节点位置。在processinginstruction, documenttype, comment, whitespace和significantwhitespace类型节点中也可以用skip方法移动指针。