11.2 基于流的XML处理
在.NET Framework中,可以使用XmlTextWriter与XmlTextReader类来对XML进行写、读处理,它们都在System.Xml命名空间中。
11.2.1 XmlTextWriter
XmlTextWriter类继承自XmlWriter类,使用它可以直接把文档写入流。同时,它也提供了快速、非缓存、只进方法的编写器,该方法生成包含XML数据的流或文件。它有三个构造函数,如下所示,可以使用它们来创建一个XmlTextWriter对象。
❑public XmlTextWriter(TextWriter w)
使用指定的TextWriter创建XmlTextWriter类的实例。
❑public XmlTextWriter(Stream w, Encoding encoding)
使用指定的流和编码方式创建XmlTextWriter类的实例。其中,如果编码方式为null,则它以UTF-8的形式写出流,并忽略ProcessingInstruction中的编码属性。
❑public XmlTextWriter(string filename, Encoding encoding)
使用指定的文件名称和编码方式创建XmlTextWriter类的实例。其中,如果该文件存在,它将截断该文件并用新内容对其进行覆盖;如果编码方式为null,则它以UTF-8的形式写出流并忽略ProcessingInstruction中的编码属性。
使用构造函数创建好XmlTextWriter对象之后,就可以使用它的相关方法来写XML内容了。常用的方法如表11-1所示。
下面就来通过一个示例演示如何使用XmlTextWriter类来写入一个XML文档。要使用XmlTextWriter写一个XML文档,首先需要创建一个XmlTextWriter对象,并在其构造函数中传入文件的物理地址与文档编码。如下面的代码所示:
string xml=Server.MapPath("MyBook.xml");
XmlTextWriter write=new XmlTextWriter(xml, null);
XmlTextWriter的可配置性很高,可以指定是否缩进文本、缩进量、在属性值中使用什么引号以及是否支持命名空间等信息。如它拥有两个属性Formatting与Indentation,可以用于设置XML数据是否按照典型的层次结构自动缩进以及用于缩进的空格数。如下面的代码所示:
writer.Formatting=Formatting.Indented;
writer.Indentation=3;
创建好XmlTextWriter对象与设置好格式之后,就可以使用WriteStartDocument方法来写入版本为“1.0”的XML声明。如下面的代码所示:
write.WriteStartDocument();
当然,这时还可以添加一些注释。如下面的代码所示:
write.WriteComment("创建时间@"+System.DateTime.Now);
如果还需要设置相关的XSL文件,可以这样来设置。如下面的代码所示:
string xsl="type=\"text/xsl\"href=\"employee.xsl\"";
writer.WriteProcessingInstruction("xml-stylesheet",xsl);
创建好上面的内容之后,就需要为MyBook.xml文档写入真正的数据内容了,如元素、节点等。下面的代码创建一个根节点MyBook:
writer.WriteStartElement("MyBook");
有了这个MyBook根节点之后,就可以在MyBook根节点下创建更加具体的内容了。如下面的代码所示:
writer.WriteComment("易学C#");
writer.WriteStartElement("book");
writer.WriteAttributeString("id","1");
writer.WriteAttributeString("name","易学C#");
writer.WriteElementString("description","一本C#学习书籍");
writer.WriteElementString("price","45");
writer.WriteEndElement();
writer.WriteComment("ASP.NET4程序设计");
writer.WriteStartElement("book");
writer.WriteAttributeString("id","2");
writer.WriteAttributeString("name","ASP.NET4程序设计");
writer.WriteElementString("description","一本ASP.NET学习书籍");
writer.WriteElementString("price","100");
writer.WriteEndElement();
最后,为了完成文档的创建,还需要调用WriteEndElement、WriteEndDocument与Close来关闭相关信息。如下面的代码所示:
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
运行上面的代码,产生的XML文档如图11-1所示。
图 11-1 MyBook.xml
11.2.2 XmlTextReader
上面阐述了如何使用XmlTextWriter类来写一个XML文档。当然,写好一个XML文档之后,就可以使用XmlTextReader类来进行各种读取操作。同样,XmlTextReader类提供对XML数据进行快速、非缓存、只进访问的读取器。
其实,该类设计的目的就是从XML文件中快速读取数据,而对系统资源(主要包括内存和处理器时间)不做很高的要求。它通过每次只处理一个节点的方式来对XML文件进行逐步操作。在XML文件的每个节点中,它能决定该节点的类型、属性和数据(如果有的话),以及其他有关该节点的信息。基于这些信息,可以选择是处理这个节点还是忽略该节点的信息,以满足各种应用程序请求的需要。它的这种处理模型也就是常说的抽取式((pll)处理模型。
关于节点,如下面的代码所示:
<description>一本ASP.NET学习书籍</description>
XmlTextReader把这个元素看做3个节点,顺序如下:
1)<description>标签被读为类型XMLNodeType.Element节点,元素的名字“description”可从XMLTextReader的Name属性中获得。
2)文本数据“一本ASP.NET学习书籍”被读为类型为XMLNodeType.Text的节点。数据“一本ASP.NET学习书籍”可从XMLTextReader的Value属性中取得。
3)</description>标签被读为类型为XMLNodeType.EndElement节点。同样,元素的名称“description”可从XMLTextReader的Name属性中获得。
XmlTextReader类常用的方法如表11-2所示。
同样,如果要使用XmlTextReader类来读取XML文档,首先需要创建一个XmlTextReader对象。在XmlTextReader对象里加载XML文件以后,开始一个循环—每次移动一个文档节点,即调用Read方法,该方法移动到最后一个节点的时候返回true。
Read方法可以进入下一个节点,然后查看该节点是否有一个值((HsValue)、该节点是否有属性((HsAttributes)。当然,也可以使用ReadStartElement方法,查看当前节点是否是起始元素,如果是起始元素,就可以定位到下一个节点上。如果不是起始元素,就引发一个XmlException。调用这个方法与调用Read后再调用IsStartElement是一样的。如下面的代码所示:
protected void Page_Load(object sender, EventArgs e)
{
string xml=Server.MapPath("MyBook.xml");
XmlTextReader reader=new XmlTextReader(xml);
StringBuilder str=new StringBuilder();
while(reader.Read())
{
if(((rader.Name=="book")&&
((rader.NodeType==XmlNodeType.Element))
{
str.Append("<b>");
str.Append(reader.GetAttribute("name"));
str.Append("</b><br/>");
reader.ReadStartElement("book");
str.Append(reader.ReadElementString("description"));
str.Append("<br/>");
str.Append(reader.ReadElementString("price"));
str.Append("<hr>");
}
}
reader.Close();
Response.Write(str);
}
示例运行结果如图11-2所示。
图 11-2 示例运行结果