C#高级编程之处理XML-连载六

时间:2010年04月12日 点击:197

23.5.1  使用 XmlTextReader

如前所述,XmlTextReader非常类似于SAX。它们最大的一个区别是SAX是一种推模型(push model),它把数据拉入应用程序中,开发人员必须接受它,而XmlTextReader是一种拉模型,把应用程序请求的数据拉入该应用程序。这样编程就有一种更简单、更直观的模型。另一个优点是拉模型(pull model)可以选择把什么数据传送到应用程序中。如果不需要所有的数据,就不需要处理它们。而在推模型中,所有的XML数据都必须由应用程序处理,无论是否需要这些数据。

下面介绍一个非常简单的示例,读取XML数据,再详细介绍XmlTextReader类,这些代码在XmlReaderSample1文件夹中。现在用下面的代码替换前面示例中的命名空间MSXML2

using System.Xml;

还需要从模块级代码中删除下述代码行:

private DOMDocument40 doc;

下面是按钮的单击事件处理程序:

protected void button1_Click (object sender, System.EventArgs e)

{

   //Modify this path to find books.xml

   string fileName = "..\\..\\..\\books.xml";

   //Create the new TextReader Object

   XmlTextReader tr = new XmlTextReader(fileName);

   //Read in a node at a time

   while(tr.Read()) 

   {

     if(tr.NodeType == XmlNodeType.Text)

      listBox1.Items.Add(tr.Value);

   }

}

这是XmlTextReader最简单的用法。首先,用XML文件名创建一个字符串对象,再创建一个新的XmlTextReader,其参数为fileName字符串。XmlTextReader目前有13种不同的构造函数重载版本,其参数是字符串(文件名和URL)、流和NameTables的不同组合(当元素或属性名出现几次后,它们就可以存储到NameTable中,这样比较操作的速度会较快)

在初始化一个XmlTextReader对象后,没有选择任何节点。只有在此时,才没有当前节点。在开始tr.Read()循环后,第一个Read()会进入文档中的第一个节点,这个节点一般是XML 声明节点。在本示例,当进入每个节点时,可比较tr.NodeType XmlNodeType枚举,找到一个文本节点后,把该文本值添加到列表框,图23-3是加载该列表框后的屏幕图。

  23-3

1. Read方法

遍历文档有几种方式,如前面的示例所示,Read()可以进入下一个节点。然后查看该节点是否有一个值(HasValue())、该节点是否有属性(HasAttributes())。也可以使用ReadStartElement()方法,查看当前节点是否是起始元素,如果是起始元素,就可以定位到下一个节点上。如果不是起始元素,就引发一个XmlException。调用这个方法与调用Read ()后再调用IsStartElement是一样的。

ReadString() ReadChars()方法都可以从元素中读取文本数据。ReadString()返回一个包含数据的字符串对象,而ReadChars()把数据读入字符数组。

ReadElementString() 类似于ReadString(),但可以把元素名作为参数。如果下一个Content节点不是起始标记,或者Name属性不匹配当前的节点Name,就会引发异常。

下面的示例说明了如何使用ReadElementString()(这段代码在XmlReaderSample2文件夹中)。注意这个示例使用FileStream,所以需要通过using语句来包括System.IO命名空间:

protected void button1_Click (object sender, System.EventArgs e)

{

   //use a filestream to get the data

   FileStream fs = new FileStream("..\\..\\..\\books.xml", FileMode.Open);

   XmlTextReader tr = new XmlTextReader(fs);

   while(!tr.EOF)

   {

      //if we hit an element type, try and load it in the listbox

      if(tr.MoveToContent() == XmlNodeType.Element && tr.FTEL=="title")

      {

         listBox1.Items.Add(tr.ReadElementString());

      }

      else

      {

         //otherwise move on

         tr.Read();

      }

}

}

while循环中,使用MoveToContent查找类型为XmlNodeType.Element和名称为title的节点。我们使用XmlTextReaderEOF属性作为循环条件。如果节点的类型不是Element,或者名称不是titleelse子句就会调用Read()方法进入下一个节点。查找到一个满足条件的节点后,就把ReadElementString()的结果添加到列表框中。这样就在listbox中添加一个书名。注意,在成功执行了ReadElementString()后,不需要调用Read()方法,这是因为ReadElementString()已经查看了整个Element,然后定位到下一个节点上。

如果删除了if子句中的&& tr.FTEL=="title",在抛出XmlException异常时,就必须捕获它。如果查看一下数据文件,就会发现MoveToContent()查找到的第一个元素是<bookstore>,因为它是一个元素,所以把检查过程放在if语句中。但是,它不包含简单的文本类型,因此会让ReadElementString()引发一个XmlException异常。解决这个问题的一种方式是把ReadElementString()调用放在它自己的函数中。现在,如果在这个函数中ReadElementString()调用失败,就可以处理错误,返回给调用函数。

下面就调用这个新方法LoadList(),把XmltextReader作为参数。进行了这些修改后,该示例如下所示(这段代码在XmlReaderSample3文件夹中)

protected void button1_Click (object sender, System.EventArgs e)

{

   //use a filestream to get the data

   FileStream fs = new FileStream("..\\..\\..\\books.xml", FileMode.Open);

   XmlTextReader tr = new XmlTextReader(fs);

   while(!tr.EOF)

   {

      //if we hit an element type, try and load it in the listbox

      if(tr.MoveToContent() == XmlNodeType.Element)

      {

         LoadList(tr);

      }

      else

      {

         //otherwise move on

         tr.Read();

      }

   }

private void LoadList(XmlReader reader)

{

   try

   {

      listBox1.Items.Add(reader.ReadElementString());

   }

   // if an XmlException is raised, ignore it.

   catch(XmlException er){}

}

运行这段代码,结果应与前面示例的结果是一样的。因此,完成这个任务有多种不同的方式。这体现了System.Xml命名空间中类的灵活性。

2. 检索属性数据

在运行示例代码时,注意在读取节点时,没有看到属性。这是因为属性不是文档结构的一部分。针对元素节点,可以检查属性是否存在,并可检索属性值。

例如,如果有属性,HasAttributes就返回true,否则就返回falseAttributeCount属性确定属性的个数。GetAttribute方法按照名称或索引来获取属性。如果要一次迭代一个属性,就可以使用MoveToFirstAttribute() MoveToNextAttribute()方法。

下面的示例迭代XmlReaderSample4中的属性:

protected void button1_Click (object sender, System.EventArgs e)

{

   //set this path to match your data path structure

   string fileName = "..\\..\\..\\books.xml";

   //Create the new TextReader Object

   XmlTextReader tr = new XmlTextReader(fileName);

   //Read in node at a time       

   while(tr.Read())

   {

      //check to see if it's a NodeType element

      if(tr.NodeType == XmlNodeType.Element) 

      {

         //if it's an element, then let's look at the attributes.

         for(int i = 0; i < tr.AttributeCount; i++) {

            listBox1.Items.Add(tr.GetAttribute(i));

      }

}

}

这次查找元素节点。找到一个节点后,就迭代其所有的属性,使用GetAttribute()方法把属性值加载到列表框中。在本例中,这些属性是genrepublicationdateISBN

智动软件

赞助商链接

热门内容

相关内容

联系我们

联系方式