XPath祖先或自我解决顺序

时间:2016-04-27 20:22:14

标签: xml xpath

所以我试图使用XPath(1.0)来获取某个类型的所有元素,其本身或任何祖先都具有特定的参数值。诀窍是参数可以是值列表,所以我不能只查找@parameter =' value'。这是我案例的文档示例,让我们说我正在寻找外部参照,他们或他们的任何祖先都有平台=" mobile":

<doc>
    <block>
        <xref platform="mobile desktop">1</xref>
    </block> 
    <block platform="mobile">
        <xref platform="desktop">2</xref>
    </block>
    <block platform="desktop">
        <xref platform="mobile">3</xref>
    </block>
</doc>

我(在一些帮助下)提出了以下几乎可以实现的XPath:

//xref[contains(concat(' ', normalize-space(ancestor-or-self::*/@platform), ' '), ' mobile ')]

目标是让concat同时连接外部参照和祖先的所有平台值,然后查看移动设备是否在那里。所以在示例文档中它应该返回所有3个外部参照,但它不会,它会省略第3个外部参照。我认为祖先或自我从根级别开始评估,所以一旦找到一个不是移动的平台,它就会失败,而不会实际检查其余的祖先或自我。再加上这种行为,concat并没有真正做任何事情,因为它只是一次查看一个节点的平台值。

有谁知道如何解决这个特殊情况?

3 个答案:

答案 0 :(得分:1)

下面的xpath

//xref[contains( @platform, 'mobile' )] | //xref/ancestor::*[contains( @platform, 'mobile' )]/xref

给了我:

<xref platform="mobile desktop">1</xref>
<xref platform="desktop">2</xref>
<xref platform="mobile">3</xref>

答案 1 :(得分:1)

我猜你可能正在使用XPath 1.0(你真的应该说),因为当选择了多个属性时,normalize-space(ancestor-or-self::*/@platform)会出错。

在XPath 1.0中,此表达式将normalize-space应用于文档顺序中节点集中的第一个节点,这意味着最外面的@platform,因为祖先在文档顺序中位于其后代之前。如果您想要最里面的@platform,请使用normalize-space((ancestor-or-self::*/@platform)[last()])

但如果您选择的元素中任何祖先都有一个包含“mobile”的@platform作为子字符串,那就是

//xref[ancestor::*/@platform[contains(., 'mobile')]]

答案 2 :(得分:1)

在XPath 1.0中,像normalize-space()这样的字符串函数需要一个字符串参数,当给定一个节点集时,它只会计算集合中的第一个节点。因此,以下表达式仅评估第一个找到的platform属性:

normalize-space(ancestor-or-self::*/@platform)

为了避免上述问题,OP的尝试XPath可以稍微调整一下如下:

//xref[
    ancestor-or-self::*[
        contains(concat(' ', normalize-space(@platform), ' '), ' mobile ')
    ]
]

演示: xpathtesterxpatheval

这样,字符串函数就会应用于各个platform元素的ancestor-or-self属性。