对XML的收集1
使用XmlReader类读取XML数据之三
5. 使用XmlReader读取XML文件
您现在已经知道了理论,本节将从示例开始演示如何使用XmlReader对象来读取XML文档。这个简单的示例利用XmlReader类的功能来解析一个名为Employees.xml的静态XML文件。程序清单4-1显示了一个XML文件,是一家企业的员工列表。
程序清单4-1 Employees.xml文件
<?xml version='1.0'?>
<employees>
<employee id="1">
<name>
<firstName>Nancy</firstName>
<lastName>Davolio</lastName>
</name>
<city>Seattle</city>
<state>WA</state>
<zipCode>98122</zipCode>
</employee>
<employee id="2">
<name>
<firstName>Andrew</firstName>
<lastName>Fuller</lastName>
</name>
<city>Tacoma</city>
<state>WA</state>
<zipCode>98401</zipCode>
</employee>
</employees>
现在您已经看到了Employees.xml文件的内容,程序清单4-2显示了用于解析Employees.xml文件的ASP.NET代码。
程序清单4-2 使用XmlReader类来处理Employees XML文件的元素
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Xml" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
//Location of XML file
string xmlFilePath = @"C:\Data\Employees.xml";
try
{
//Get reference to the XmlReader object
using (XmlReader reader = XmlReader.Create(xmlFilePath))
{
string result;
while (reader.Read())
{
//Process only the elements
if (reader.NodeType == XmlNodeType.Element)
{
//Reset the variable for a new element
result = "";
for (int count = 1;count <= reader.Depth; count++)
{
result += "===";
}
result += "=> " + reader.Name + "<br/>";
lblResult.Text += result;
}
}
}
}
catch(Exception ex)
{
lblResult.Text = "An Exception occurred: " + ex.Message;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Reading an XML File using XmlReader</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:label id="lblResult" runat="server" />
</div>
</form>
</body>
</html>
在研究代码之前,先看看程序清单4-2生成的输出,如图4-2所示。
第一步是导入执行页面所需的所有命名空间—— 用于XML解析器的.NET库,其中大部分包含在System.Xml命名空间中。
<%@ Import Namespace="System.Xml" %>
接下来,在Page_Load函数中,定义了一个包含XML文件位置的变量。然后代码通过调用XmlReader对象的Create方法在using代码块中声明了一个XmlReader对象。
using (XmlReader reader = XmlReader.Create(xmlFilePath))
图 4-2
注意:
在.NET Framework 2.0对XmlReader类的改善中,一个重要的特性是能通过调用Dispose方法来处置被XmlReader使用过的资源。XmlReader类现在已经实现了IDisposable接口。所以,现在可以在using代码块中包含XmlReader对象的创建,并且被XmlReader使用的资源将会在using代码块结束的时候自动释放。
请注意XmlReader对象不局限于读取文件。对Create()方法的各种重载可以让您从URL、流、字符串和其他Reader对象中获得XML输入。下一步是读取XML文件,这其实很简单,因为XmlReader对象就为这个目的提供了Read()方法。这个方法在遇到XML文件中的节点时返回True。在结束整个文件时返回False。只要将这个方法放入while循环中调用,就能轻易地处理整个文件。在while循环中,将会有处理元素节点的代码,为了显示的目的会将这些代码格式化。
当前节点的NodeType属性可以用于过滤元素,从而进行进一步处理。
if (reader.NodeType == XmlNodeType.Element)
在while循环中余下的代码将确保输出能够显示在浏览器中而被正确地格式化。请特别注意Depth属性的使用,该属性具有一个表示当前节点在树层次结构中的深度的整数值。例如,<employees>元素的深度是0,<employee>元素的深度是1,依次类推。
注意:
由Read方法读取的节点并不对应于一个完整的XML元素。例如,看看这个XML 元素:
<city>Seattle</city>
从XmlReader的角度来说,这3个节点将按照如下顺序读取:
(1) 一个对应于打开标签的节点。这个节点具有Element类型且其本地名为“city”。
(2) 一个对应于数据的节点。这个节点具有Text类型且值为“Seattle”。
(3) 一个对应于关闭标签的节点。这个节点具有EndElement类型且本地名为“city”。
以上是关于如何处理元素的内容。但是如何处理包含在每个元素之内的属性呢?在后面的小节中,您将会看到使用XmlReader类处理属性的步骤。
处理异常
当XmlReader类处理XML文件的时候,它会检查XML文件的格式良好情况并分解外部引用(如果有)。问题会出现在各个方面,包括指定的文件未找到或者不能打开等明显的错误。任何XML语法错误都将产生一个System.Xml.XmlException类型的异常。这个类的Message属性将返回一个关于此错误的描述性消息(所有的Exception类都将如此)。这个消息还包括了错误发生的行号和位置。XmlException类的两个附加属性—— LineNumber和LinePosition—— 可以分别返回错误的行号和字符位置。您可以按照需要使用这些信息。比如,您的程序可以打开和显示带有指示错误发生位置的指针的不良XML文件。
在使用XmlReader类(和其他XML相关类)的程序中处理异常XML将使用如下两个常用模式:
(1) 捕捉XmlException类型的异常来处理XML解析错误。
(2) 捕捉其他异常来处理其他类型错误。
为了简化起见,前面程序清单4-2中显示的示例没有创建两个catch块,而是在一个单独的catch块中处理了包括XmlException在内的所有异常。
处理XML文件中的属性
XML元素可以包含属性,这些属性由名称/值对组成并总是字符串数据。在XML文件示例中,employee元素具有id属性。在您查看程序清单4-2中的示例代码时,您可能注意到当节点读入的时候,您没有看见任何属性。这是因为并没有将属性看作是文档结构的一部分。当您位于文档节点上时,可以检查属性是否存在,还可以选择获取属性值。例如,如果存在任何属性,HasAttributes属性将返回true;否则,将返回false。AttributeCount属性告诉您有多少个属性,而GetAttribute()方法通过名称或者索引获得属性。如果想以一次获取一个属性的形式进行迭代,您还可以使用MoveToFirstAttribute()和MoveToNextAttribute()方法。
本节将在前面示例的基础上添加能够处理XML文件中的属性的功能。程序清单4-3讨论了添加至前面示例中的、用于属性处理的代码。
程序清单4-3 处理XML文件中的属性
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Xml" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
//Location of XML file
string xmlFilePath = @"C:\Data\Employees.xml";
try
{
//Get reference to the XmlReader object
using (XmlReader reader = XmlReader.Create(xmlFilePath))
{
string result;
while (reader.Read())
{
//Process only the elements
if (reader.NodeType == XmlNodeType.Element)
{
//Reset the variable for a new element
result = "";
for (int count = 1; count <= reader.Depth; count++)
{
result += "===";
}
result += "=> " + reader.Name;
lblResult.Text += result;
//Check if the element has any attributes
if (reader.HasAttributes)
{
lblResult.Text += " (";
for (int count = 0; count < reader.AttributeCount; count++)
{
//Read the current attribute
reader.MoveToAttribute(count);
lblResult.Text += reader.Name;
}
lblResult.Text += ")";
//Instruct the parser to go back the element
reader.MoveToElement();
}
lblResult.Text += "<br/>";
}
}
}
}
catch(Exception ex)
{
lblResult.Text = "An Exception occurred: " + ex.Message;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Reading an XML File and attributes using XmlReader</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:label id="lblResult" runat="server" />
</div>
</form>
</body>
</html>
您可以看到,程序清单4-3与原来的程序清单4-2相比只有一个主要的改变—— 为读取器在XML文件中遇到的每个元素处理其属性。
程序清单4-3在开始阶段使用HasAttributes属性检查当前节点的属性。请注意,如果当前节点具有多个属性,这个属性将设置为true。
if (reader.HasAttributes)
XmlReader的AttributeCount属性保存了属性的总数目,用于在属性集中进行循环。MoveToAttribute()方法将读取器定位于集合中的下一个属性,然后使用Name属性获得该属性的名称。
for (int count = 0; count < reader.AttributeCount; count++)
{
//Read the current attribute
reader.MoveToAttribute(count);
lblResult.Text += reader.Name;
}
在当前节点属性的迭代完成之后,MoveToElement()方法将重置读取器的位置,然后如果下一个节点存在就处理下一个节点。图4-3显示了程序清单4-3的输出。
图 4-3
最后两个示例显示了如何学习XML文件中的信息结构,而完全忽略了包含在每个属性和元素之内的数据。在实际应用中,您会像关注元素和属性名称一样关注每个元素内的数据。下一节将对这方面进行讨论并显示如何读取包含在这些元素和属性之中的数据。
****************************************************************************************************************
备注
--------------------------------------------------------------------------------
如果 text 为 null 或 String.Empty,则此方法编写没有数据内容的注释,例如 <!---->。
如果 text 包含由两个短划线"--"组成的无效序列,则 XmlWriter 会引发 ArgumentException,或者在短划线之间插入空格(即"- -"),以便文本成为有效的 XML 注释(Create 方法创建的 XmlWriter 对象)。
示例
--------------------------------------------------------------------------------
下面的示例在流中导航以确定当前节点类型,然后使用 XmlWriter 输出 XmlReader 内容。
StringBuilder output = new StringBuilder();
String xmlString =
@"<?xml version='1.0'?>
<!-- This is a sample XML document -->
<Items>
<Item>test with a child element <more/> stuff</Item>
</Items>";
// Create an XmlReader
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
XmlWriterSettings ws = new XmlWriterSettings();
ws.Indent = true;
using (XmlWriter writer = XmlWriter.Create(output, ws))
{
// Parse the file and display each of the nodes.
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
writer.WriteStartElement(reader.Name);
break;
case XmlNodeType.Text:
writer.WriteString(reader.Value);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
break;
}
}
}
}
OutputTextBlock.Text = output.ToString();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述