使用 XPath,如何根据节点的文本内容和属性值来选择节点?

Posted

技术标签:

【中文标题】使用 XPath,如何根据节点的文本内容和属性值来选择节点?【英文标题】:Using XPath, How do I select a node based on its text content and value of an attribute? 【发布时间】:2010-12-31 06:09:50 【问题描述】:

鉴于此 XML:

<DocText>
<WithQuads>
    <Page pageNumber="3">
        <Word>
            July
            <Quad>
                <P1 X="84" Y="711.25" />
                <P2 X="102.062" Y="711.25" />
                <P3 X="102.062" Y="723.658" />
                <P4 X="84.0" Y="723.658" />
            </Quad>
        </Word>
        <Word>
        </Word>
        <Word>
            30,
            <Quad>
                <P1 X="104.812" Y="711.25" />
                <P2 X="118.562" Y="711.25" />
                <P3 X="118.562" Y="723.658" />
                <P4 X="104.812" Y="723.658" />
            </Quad>
        </Word>
    </Page>
</WithQuads>

我想查找文本为“July”且 Quad/P1/X 属性大于 90 的节点。因此,在这种情况下,它不应返回任何匹配项。但是,如果我使用 GT (>) 或 LT (

所以:

//Word[text()='July' and //P1[@X < 90]]

将返回 true,也将返回 true

//Word[text()='July' and //P1[@X > 90]]

如何在 P1@X 属性上正确地约束它?

此外,假设我有多个 Page 元素,用于不同的页码。我将如何另外限制上述搜索以查找具有text()='July', P1@X &lt; 90 和 Page@pageNumber=3 的节点?

【问题讨论】:

对于这个特定的 XML 可能不是每个读者都清楚的一个重要的事情是,因为这个 XML 使用混合内容模型,所以很难将元素与 XPath 匹配。我最近遇到了这个问题,并且对我的 XPath 生疏了,我正要得出结论,在我在下面找到 Michael Kay 的答案之前,无法匹配混合内容元素。我找不到任何其他关于混合内容和 XPath 的缺陷的参考资料。 你的问题回答了我的问题。在 XPath 中对字符串使用“单撇号”非常重要,而不是“双引号”。这真的非常重要。谢谢你的线索。 【参考方案1】:

通常我会认为在 XPath 中使用不带前缀的 // 是一种不好的气味。

试试这个:-

/DocText/WithQuads/Page/Word[text()='July' and Quad/P1/@X > 90]

您的问题是您使用了//P1[@X &lt; 90],它从文档的开头开始并开始搜索任何P1,因此它总是正确的。同样//P1[@X &gt; 90] 始终为真。

【讨论】:

我很惊讶这实际上是可行的,因为 Michael Kay 的回答中解决了空格问题。我在几个不同的 XPath 评估器中尝试了这个答案,但两者都不匹配。一旦我使用“normalize-space”切换到谓词,我就成功匹配了。 您可以使用.//P1 在当前级别开始搜索,而不是指定固定路径【参考方案2】:

除了“//”问题之外,这个 XML 是对混合内容的一种非常奇怪的使用。如果任何子文本节点恰好等于 July,谓词 text()='July' 将匹配该元素,这在您的示例中不正确,因为周围有空格。根据源 XML 的确切定义,我会选择 [text()[normalize-space(.)='July'] and Quad/P1/@X &gt; 90]

【讨论】:

谢谢你,迈克尔。我想知道空格....我在粘贴到堆栈溢出之前格式化了示例,但是我的源 XML 都是“紧密的”。当我针对格式化版本运行 xpath 时,它确实无法正常工作。我会尝试使用 normalize-space(.)

以上是关于使用 XPath,如何根据节点的文本内容和属性值来选择节点?的主要内容,如果未能解决你的问题,请参考以下文章

xpath 轴定位表达方式

XPath怎样根据一个元素定位另外一个元素?

Python爬虫编程思想(42):XPath实战:匹配属性

如何匹配文本节点然后使用 XPath 跟随父节点

XPath注入

XPath如何定位dom节点