2016-04-27 84 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')]。 –