1

为什么 XPath over aSystem.Xml.XmlDocument找不到相邻的文本和 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()

4

1 回答 1

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

实际上,尝试通过其他 XPath 选择“文本”DOM 节点意味着:

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

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

您看到的是两种模型的混合——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

于 2016-04-08T06:31:42.867 回答