XML 搜索和验证(XmlDocument、XPath to XmlDocument、LINQ to XDocument)

       对数情况下,并不需要处理整个 XML 文档,只是从中抓取部分信息,使用的方法依据使用的类。

  • XmlDocument
    • 简单情况:使用 GetElementsByTagName()
    • 复杂情况:使用 XPath 语言。
  • XDocument
    • 简单情况:内建的搜索方法(如 Elements())
    • 复杂情况:LINQ 表达式

 

搜索 XmlDocument

       使用 XmlDocument 执行查询最简单的方法是使用 XmlDocument. GetElementsByTagName(),返回一个 XmlNodeList 。

string xmlFile = Server.MapPath("DvdList.xml");
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
 
StringBuilder str = new StringBuilder();
XmlNodeList nodes = doc.GetElementsByTagName("Title");
foreach (XmlNode node in nodes)
{
    str.Append("Found: <b>");
    str.Append(node.ChildNodes[0].Value);
    str.Append("</b><br />");
}
Response.Write(str);

 

       更复杂的 XML 文档几乎总是有命名空间甚至多个命名空间。遇到这样的情况,可以使用 GetElementsByTagName()方法的重载版本:

XmlNodeList nodes = doc.GetElementsByTagName("Title","http://mycompany/OrderML");

       如果要匹配给定命名空间下的所有标签,也可以使用星号(*)作为元素名称:

XmlNodeList nodes = doc.GetElementsByTagName("*",http://mycompany/OrderML);

 

 

使用 XPath 搜索 XmlDocument

       GetElementsByTagName()方法功能非常有限。只允许你基于元素的名称搜索,你不能够基于其他条件过滤,比如某个元素的值或者特性的内容。

       XPath 是一个更为强大的标准,使用和路径相似的符号允许你获取感兴趣的文档部分。

 

XPath 基本语法:

/

从根节点开始创建绝对路径。(/DvdList/DVD 选择根元素<DvdList>下所有子元素<DVD>)

//

搜索节点所有嵌套层,递归搜索子节点。(//DVD/Title 搜索DVD元素的所有子元素Title)

@

选择节点的某个特性

*

选择路径中的任意元素 (/DvdList/DVD/*)

|

组合多个路径。(/DvdList/DVD/Title | /DvdList/DVD/Director)

.

表示当前节点

..

表示父节点

[]

定义一个选择条件,它可以测试包含节点或特性的值。

starts - with

这个函数根据包含元素以什么样的文本开头获取元素 /…/DVD[starts-with(Title.'P')]

position

基于位置获取元素,从1开始计数 /…/DVD[position()=2] 等效于简写的 /…/DVD[2]

count

这个函数统计匹配名称的元素个数。count(DVD) 返回 <DVD> 元素的个数

注解:

       要区分两个相关的术语:

  • 子节点:父节点下一层的节点,只是第一层。
  • 后代节点:父节点下所有的嵌套节点,即所有子节点的子节点的子节点的…
string xmlFile = Server.MapPath("DvdList.xml");
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
 
StringBuilder str = new StringBuilder();
// 选择 Title 标签,查询条件是 父节点(DVD) 的特性相匹配的
XmlNodeList nodes = doc.SelectNodes("/DvdList/DVD/Title[../@Category='Science Fiction']");
foreach (XmlNode node in nodes)
{
    str.Append("Found: <b>");
    str.Append(node.ChildNodes[0].Value);
    str.Append("</b><br />");
}
Response.Write(str);

 

 

使用 LINQ 搜索 XDocument

       你已经知道了 XElement 类的 XElement()和 XElements()方法过滤出特定名称的元素,不过,这些方法只向下深入了一层。

       最简单的解决办法是使用这些方法:

  • ElementAfterSelf()、ElementBeforeSelf():找到兄弟元素
  • Descendants():返回此文档或元素的子代元素集合
  • Ancestors():返回此节点的上级元素的集合。

       下面的示例找到文档里任意层级的所有电影标题:

string xmlFile = Server.MapPath("DvdList.xml");
XDocument doc = XDocument.Load(xmlFile);
foreach (XElement element in doc.Descendants("Title"))
{
    // do something ...
}

 

       把元素集合放到 LINQ 表达式后,就可以使用各种已经熟悉的操作。也就是说,你可以使用排序、过滤、分组和投影区取得希望的数据:

string xmlFile = Server.MapPath("DvdList.xml");
XDocument doc = XDocument.Load(xmlFile);
IEnumerable<XElement> matches = from DVD in doc.Descendants("DVD")
                                where (int)DVD.Attribute("ID") < 3
                                select DVD.Element("Title");

 

       把数据转换为其他格式通常更有用。下面的查询创建一个匿名类型,它组合标题和价格,并按价格降序排序,然后绑定到网格显示:

string xmlFile = Server.MapPath("DvdList.xml");
XDocument doc = XDocument.Load(xmlFile);
var matches = from DVD in doc.Descendants("DVD")
              orderby (decimal)DVD.Element("Price") descending
              select new
              {
                  Moive = (string)DVD.Element("Title"),
                  Price = (decimal)DVD.Element("Price")
              };
GridView1.DataSource = matches;
GridView1.DataBind();
 
// 一定不要忘记进行类型转换这个步骤
// 这个步骤用于从完整的 XElement 对象取得值

image

 

       LINQ to XML 还包含一组扩展方法,它们针对元素集合工作:

IEnumerable<string> matches =
    from title in doc.Root.Elements("DVD").Elements("Title")
    select (string)title;

       这里要注意的是,第二次调用的 Elements("Title") 实质上是针对第一次的结果 IEnumerable<T> 调用的,它是一个扩展方法。由 System.Xml.Linq.Extensions 类进行了定义,专为处理 IEnumerable<XElement> ,在某些场合,比如你拥有以不同方式从 XML 文档不同部分构件的 IEnumerable<XElement> 集合时,这些扩展方法就比较有用。

       Extensions 类还定义了另外几个应用到 XElement 集合的扩展方法:Ancestors()、AncestorsAndSelf()、Attributes()、Descendants()、DescendantsAndSelf()。

 

 

验证 XML 内容

       我们已经知道了一系列用于读取和解析 XML 数据的策略。但如果用其中任何一种方法尝试读取一个无效的 XML 内容时,就会得到一个错误。换句话说,所有这些类都要求一个格式良好的 XML 。

 

基本架构

       XML 格式通常用一个展示其必需结构和数据类型的 XML 架构来规范它的内容。对于 DVD 列表文档,可以创建这样一个相似的 XML 架构:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="DvdList" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="DvdList">
    <xs:complexType>
      <xs:sequence maxOccurs="unbounded">
        <xs:element name="DVD" type="DVDType" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
 
  <xs:complexType name="DVDType">
    <xs:sequence>
      <xs:element name="Title" type="xs:string" />
      <xs:element name="Director" type="xs:string" />
      <xs:element name="Price" type="xs:decimal" />
      <xs:element name="Starring" type="StarringType" />
    </xs:sequence>
    <xs:attribute name="ID" type="xs:integer" />
    <xs:attribute name="Category" type="xs:string" />
  </xs:complexType>
 
  <xs:complexType name="StarringType">
    <xs:sequence maxOccurs="unbounded">
      <xs:element name="Star" type="xs:string" />
    </xs:sequence>
  </xs:complexType>  
</xs:schema>

 

 

验证 XmlDocument

       要用一个架构验证 XML 文档,可以借助 XmlValidatingReader 类。

       执行验证的第一步是引入命名空间 System.Xml.Schema,它包含的类型有 XmlSchema 和 XmlSchemaCollection 等:

using System.Xml.Schema;

       下面的示例演示如何创建一个使用 DvdList.xsd 文件的带验证的阅读器,以及如何使用它验证 DvdList.xml 中的 XML 是有效的:

// 创建 XmlReaderSettings,它指定你想使用的架构
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
string xsdFile = Server.MapPath("DvdList.xsd");
settings.Schemas.Add("", xsdFile);
 
// 创建验证读取器并验证文档
string xmlFile = Server.MapPath("DvdList.xml");
FileStream fs = new FileStream(xmlFile, FileMode.Open);
XmlReader vr = XmlReader.Create(fs, settings);
while (vr.Read())
{
    // Process document here.
    // if an error is found,an exception will be thrown.
}
vr.Close();

       做一个小小的改动:

<DVD ID="A" Category="Drama">

       现在再次验证时,XmlSchemaValidationException (来自 System.Xml.Schema 命名空间)异常被抛出,它提示你有无效的数据类型。

 

       不是捕获错误,而是可以响应 ValidationEventHandler 事件。如果你响应了这个事件,它会提供错误信息但不会抛出异常:

settings.ValidationEventHandler += ValidationEventHandler;

       对应的事件处理程序:

void ValidationEventHandler(object sender, ValidationEventArgs e)
{
    lblInfo.Text = "Erroe: " + e.Message;
}

 

 

使用 XDocument 进行验证

       虽然 XDocument 没有嵌入验证功能,但 .NET 包含扩展方法。需要引入 System.Xml.Schema ;这个命名空间里也有一个 Extensions 类,它有一个可以在 XElement 和 XDocument 中使用的 Validate()方法:

{
    string xmlFile = Server.MapPath("DvdList.xml");
    string xsdFile = Server.MapPath("DvdList.xsd");
    
    XDocument doc = XDocument.Load(xmlFile);
    
    XmlSchemaSet schemas = new XmlSchemaSet();
    schemas.Add("", xsdFile);
    
    doc.Validate(schemas,ValidationEventHandler);
}
 
 
void ValidationEventHandler(object sender, ValidationEventArgs e)
{
   // do something ...
}

posted on 2012-08-27 13:34  SkySoot  阅读(2268)  评论(0编辑  收藏  举报

导航