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


71

鉴于此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元素上得到一个匹配项。如果使用eq(=),则不会匹配。

所以:

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

将返回true,

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

如何在P1 @ X属性上适当地限制它?

另外,假设我有多个Page元素,用于不同的页码。我将如何另外约束上述搜索以找到带有text()='July', P1@X < 90和Page的节点@pageNumber=3


对于每个读者来说可能并不明显的这种特殊XML需要注意的重要一点是,由于该XML使用混合内容模型,因此很难将元素与XPath匹配。我最近遇到了这个问题,由于对我的XPath感到生疏,我将得出一个结论,直到我在下面找到Michael Kay的答案,才能匹配混合内容元素。我还没有找到其他参考来讨论混合内容和XPath的陷阱。
Michael Sorens 2010年

您的问题回答了我的问题。在XPath中对字符串使用“单撇号”,而不是“双引号”,这一点非常重要。这真的很重要。谢谢你的提示。
KrzysztofJabłoński2012年

Answers:


78

通常,我会将未前缀的// //用作XPath中的难闻气味。

尝试这个:-

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

您的问题是,您使用了//P1[@X < 90]从文档开头开始的,并开始搜索任何内容,P1因此它永远都是正确的。同样//P1[@X > 90]总是如此。


1
实际上,由于迈克尔·凯(Michael Kay)回答中提到的空格问题,使该方法行之有效,令我感到惊讶。我在几个不同的XPath评估程序中尝试了此答案,但均未能与之匹配。一旦我切换到带有“ normalize-space”的谓词,那么我就成功进行了匹配。
Michael Sorens 2010年

您可以使用.//P1当前级别开始狩猎,而不必指定固定路径
Mark Jeronimus

27

除了“ //”问题之外,此XML是混合内容的非常奇怪的用法。text()='July'如果任何子文本节点完全等于July,则谓词将与元素匹配,由于周围的空格,在您的示例中这不是正确的。根据源XML的确切定义,我会选择[text()[normalize-space(.)='July'] and Quad/P1/@X > 90]


谢谢迈克尔。我想知道空白...。我在粘贴到堆栈溢出之前格式化了样本,但是我的源XML全部“紧密”。当我对格式化版本运行xpath时,确实确实无法正常工作。我将尝试使用normalize-space(。)
marc esher 2009年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.