• XmlDocument的XPath操作


    某个客户询问我关于SelectSingleNode和SelectNodes的XPath操作,问题如下:

    【xml】

    <root>
      <dsobject classname="Rendition">
        <contentelements>
          <contentelement>Tansion</contentelement>
        </contentelements>
      </dsobject>
    
      <dsobject classname="Rendition">
        <contentelements>
          <contentelement>Herry</contentelement>
        </contentelements>
      </dsobject>
    
      <dsobject classname="Rendition">
        <contentelements>
          <contentelement>Jack</contentelement>
        </contentelements>
      </dsobject>
    </root>

    现在他要求“筛选出所有名称为dsobject,classname等于Rendition”,输出其contentelement的数据。

    他这样做:

    [C#]

    foreach (XmlNode item in document.SelectNodes("//dsobject[@classname='Rendition']"))
    {
      XmlNode oneNode = item.SelectSingleNode("//contentelement");
      string inner = oneNode.InnerText;
    }
    

    [VB.NET]

    For Each item As XmlNode In document.SelectNodes("//dsobject[@classname='Rendition']")
    	Dim oneNode As XmlNode = item.SelectSingleNode("//contentelement")
    	Dim inner As String = oneNode.InnerText
    Next

    粗看先是从xml文档全部选出classname属性值为Rendition的全部dsobject(外循环),内部再从每个dsobject节点内部筛选出contentelement节点并输出包含的数值。但是实际上输出的结果只是三个“Tansion”。

    究其原因,是因为XPath语法的特殊性:凡是以“//”开头的,都是无条件以整个xml的根节点开始遍历的。因此item.SelectSingleNode不要误以为是接着上面的dsobject节点往下检索,而是从头开始的!因此遍历的时候总是遍历到第一个dsobject中的contentelement的内部数值。

    同样地,凡是以“/”开头的,都是无条件人为指定从根节点开始的绝对路径搜索,与XmlNode上下文毫无关系(比如要查询第一个contentelement,用绝对路径甚至可以这样写):

    [C#]

    Console.WriteLine(document.SelectSingleNode("/root/dsobject/contentelements/contentelement").InnerText);
    Console.WriteLine(document.DocumentElement.SelectSingleNode("/root/dsobject/contentelements/contentelement").InnerText);

    [VB.NET]

    Console.WriteLine(document.SelectSingleNode("/root/dsobject/contentelements/contentelement").InnerText)
    Console.WriteLine(document.DocumentElement.SelectSingleNode("/root/dsobject/contentelements/contentelement").InnerText)
    

    显然,以/开头无论XmlNode是什么,总是被忽略且从指定的root=>dsobject=>contentelements=>contentment这样的顺序开始检索(绝对路径)。

    至于和上下文相关的,就是直接写名字;比如:

    [C#]

    Console.WriteLine(document.SelectSingleNode("root/dsobject/contentelements/contentelement").InnerText);
    Console.WriteLine(document.DocumentElement.SelectSingleNode("dsobject/contentelements/contentelement").InnerText);
    

    [VB.NET]

    Console.WriteLine(document.SelectSingleNode("root/dsobject/contentelements/contentelement").InnerText)
    Console.WriteLine(document.DocumentElement.SelectSingleNode("dsobject/contentelements/contentelement").InnerText

    显然,document的根节点是“#document”(特殊节点,xml中不存在),那么相对它而言下面的节点是root/dsobject/contentelments/contentelement。不过document.DocumentElement本身就是root,因此第二句代码中root就不能再写了,不然会发生找不到节点(因为不存在root=>root=>……这样的节点)。

    SelectNodes也符合这样的特点,这里就不再叙述了。

  • 相关阅读:
    深入理解 IE haslayout
    electron的应用
    自动化批量录入Web系统
    Flask + Vue的一个示例
    如何从git仓库里下载单个文件夹
    Django项目设置首页
    简单更改Django Admin登录页面
    Flask web项目使用.flaskenv文件
    Flask 里url_for的使用
    使用Flask-migrate迁移数据库
  • 原文地址:https://www.cnblogs.com/ServiceboyNew/p/2498444.html
Copyright © 2020-2023  润新知