【问题标题】:XPath expression: selecting text nodes between element nodesXPath 表达式:在元素节点之间选择文本节点
【发布时间】:2017-01-23 01:54:51
【问题描述】:

基于以下 HTML,我想提取 TextA、TextC 和 TextE。

<div id='content'>
    TextA
    <br/>
    <br/>
    <p>TextB</p>
    TextC
    <br/>
    TextC
    <p>TextD</p>
    TextE
</div>

我试图像这样得到 TextC,但没有得到我想要的结果:

  • 查询:
    //*[preceding::p[contains(.,"TextB")] and following::p[contains(.,"TextD")]]
  • 预期结果:
    ["TextC", &lt;br/&gt;, "TextC"]
  • 实际结果:
    [&lt;br/&gt;]

有没有办法在不使用//div/text()[1] 之类的索引的情况下选择文本节点?

【问题讨论】:

  • 你的问题很不清楚。在第一行中,您说“我想提取 TextA、TextC 和 TextE”,但稍后您又谈到想要选择 ["TextC", &lt;br/&gt;, "TextC"]。请清楚地解释你想要做什么。
  • 知道了。我确实想提取所有上述文本节点,我的查询只是我尝试这样做的一个示例。

标签: xpath textnode


【解决方案1】:

这两个文本节点不在 XPath 结果中的原因是* 只匹配元素。要同时匹配元素和文本节点,您可以使用 node() 代替:

//node()[preceding::p[contains(.,"TextB")] and following::p[contains(.,"TextD")]]

Demo

或者如果您只想获取文本节点,即排除&lt;br/&gt;,您可以使用text() 而不是node()

//text()[preceding::p[contains(.,"TextB")] and following::p[contains(.,"TextD")]]

【讨论】:

  • 修复了代码中的复制粘贴错误。 +1。顺便说一句@OP,如果您使用preceding-siblingfollowing-sibling 而不是precedingfollowing,您可能会获得更好的效率,假设您可以确定您所指的&lt;p&gt; 元素与文本节点。您甚至可能需要preceding-sibling::p[1],以获得更高的特异性和效率,具体取决于您将该技术应用于不同 XML 输入的广泛程度。
  • 这正是我一直在寻找的。谢谢!