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也符合这样的特点,这里就不再叙述了。

你可能感兴趣的:(document)