【问题标题】:Why does XPath over a System.Xml.XmlDocument not find adjacent text and CData nodes?为什么 System.Xml.XmlDocument 上的 XPath 找不到相邻的文本和 CData 节点?
【发布时间】:2016-07-29 07:53:50
【问题描述】:

为什么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()

【问题讨论】:

  • 考虑将问题更改为Why does XPath over a System.Xml.XmlDocument not find adjacent text and CData nodes? 作为整个问题,并且您的答案特定于 .NET 框架中的 DOM 实现以及您的假设“我们可以从上面看到 CDATA 节点具有文本节点是下一个兄弟节点,因此您会认为表达式 /root/test/text()" 在不知道任何 CDATA 节点的 XPath 数据模型中没有基础。
  • @Martin,好点子 - 谢谢。我已经更新了 OP :)

标签: c# xml xpath cdata xpath-1.0


【解决方案1】:

在处理 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')]");

将给出与 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

【讨论】:

    猜你喜欢
    • 2018-11-06
    • 2017-07-12
    • 2017-06-29
    • 2019-04-11
    • 2015-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多