zoukankan      html  css  js  c++  java
  • 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 ...
    }
  • 相关阅读:
    odoo 错误 Resource interpreted as Stylesheet but transferred with MIME type application/x-css:
    Android架构师之路-架构到代码的演练
    Android架构师之路-架构师的决策
    EventBus
    Android架构师之路-UML图形思考
    Android架构师之路-oop
    EventBus
    java定义接口监听器详解
    INSTALL_FAILED_NO_MATCHING_ABIS
    android---NDK开发helloworld(jni)
  • 原文地址:https://www.cnblogs.com/SkySoot/p/2658421.html
Copyright © 2011-2022 走看看