为什么XPath over System.Xml.XmlDocument找不到相邻的文本和CData节点?

时间:2016-04-08 06:31:43

标签: c# xml xpath cdata xpath-1.0

为什么System.Xml.XmlDocument上的XPath找不到相邻的文本和CData节点?

var raw_xml = @"
<root>
    <test>
        <![CDATA[This is a CDATA node]]>And this is an adjacent text node
    </test>
</root>
";

var doc = new XmlDocument();
doc.LoadXml(raw_xml);

var results = doc.SelectNodes("/root/test/text()");
Console.WriteLine(results.Count); // gives: 1
Console.WriteLine(results[0].Value); // gives: This is a CDATA node
Console.WriteLine(results[0].Name); // gives: #cdata-section
Console.WriteLine(results[0].GetType().FullName); // gives: System.Xml.XmlCDataSection
Console.WriteLine(results[0].NextSibling.Name); // gives: #text
Console.WriteLine(results[0].NextSibling.Value.Trim()); // gives: And this is an adjacent text node

我们可以从上面看到CDATA节点有文本节点作为它的下一个兄弟,所以你会认为表达式/root/test/text()会找到它。

与XPath相同的结果:/root/test/node()

1 个答案:

答案 0 :(得分:2)

使用XML文档时,您可能习惯于文档对象模型(DOM),其中CDATA节点与文本节点分开。 XPath数据模型将text()个节点视为所有相邻的CDATA和文本DOM节点兄弟节点。

因此,尝试编写将不是相邻系列的第一个特定DOM文本/ CDATA节点的查询将失败,例如:

var results = doc.SelectNodes("/root/test/text()[starts-with(., 'And')]");
Console.WriteLine(results.Count); // gives: 0

确实,试图选择&#34;文本&#34;其他XPath的DOM节点意味着:

var results = doc.SelectNodes("/root/test/text()[contains(., 'text node')]");

将提供与OP中的初始/root/test/text()查询相同的结果。

你看到的是两个模型的混合 - 来自XPath查询的结果被转换回DOM节点;所以它为你提供了第一个text()节点,在这种情况下,它是CDATA节点。

如果您确实需要在XPath中使用单独的文本和CDATA节点,则需要确保XML注释分隔源文档中的节点,如下所示:

<root>
    <test>
        <![CDATA[This is a CDATA node]]><!-- separator comment -->And this is an adjacent text node
    </test>
</root>

这样

var results = doc.SelectNodes("/root/test/text()");
Console.WriteLine(results.Count);

将提供2