2016-04-27 70 views
1

因此,我试图使用XPath(1.0)来获取某个类型的所有元素,而这些元素本身或任何祖先都具有特定的参数值。诀窍是该参数可以是一个值列表,所以我不能只查找@ parameter ='value'。这是我的情况下文档的一个例子,比方说我在寻找外部参照元素这其中一方或任何其祖先有平台=“手机”:XPath祖先或自我解析命令

<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并没有做任何事情,因为它只是一次查看一个节点的平台值。

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

回答

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 ') 
    ] 
] 

演示:xpathtester,xpatheval

这样字符串函数应用于个人platform属性ancestor-or-self元素。

+0

谢谢,这正是我一直在寻找的!我知道我曾经尝试过类似的东西,所以我翻遍了我的尝试,发现了一个就像这样,但在*之后有一个/所以它不起作用。说实话,我没有理解,知道为什么/不应该在那里,但谢谢! –

+0

@AndresMata欢迎您!我认为它是:predicate('[[...]')需要一个上下文节点来应用,而上下文是左边的节点。因此'/ [...]'从来不是正确的语法,因为除了路径分隔符外,谓词的左边没有任何东西,与'/ ancestor-or-self :: * [...]对比' 'ancestor-or-self :: *'是谓词的上下文 – har07

1

下面

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

中的XPath给我:

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

嗯,这可能是因为我对我的问题并不十分清楚,但是我发现这个xpath存在一些问题......可能有另一个平台值为“fakemobile”,所以只需询问if它包含“移动”子字符串是不够的,它可能是不同平台值的一部分。另一个问题是它并不总是具有价值的外部参照的直接祖先,它可能是任何祖先......但是非常感谢这个 –

+0

然后让你的问题清楚请...谢谢。 – SomeDude

1

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

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

但是,如果你选择其中任何祖先具有包含“移动”作为子字符串的@platform元件,这将是

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

对不起,我只是在学习XPath,所以我没有意识到版本差异。我在Java 8中使用javax.xml.xpath库,根据文档它符合XPath 1.0。有没有简单的方法来扩展这个答案,而不是移动平台的子串,以便它匹配列表中给出的值之一?例如,如果它可以匹配platform =“desktop mobile”,但不匹配platform =“desktop mobileBrowser”。我有几个这样的例子。 –

+0

如果您使用的是Java,那么没有理由限制为XPath 1.0:有几款产品实现XPath 2.0或3.0或XQuery,这些功能的功能更加强大:我自己的Saxon产品就是其中之一。然而,你可以用你已经使用的技巧在1.0中进行匹配:将谓词改为'[contains(concat('',normalize-space(。),''),'mobile')]。 –