2010-10-13 70 views
15

我想構造一個XPath查詢,它將返回一個「div」或「table」元素,只要它具有包含文本「abc」的後代。有一點需要注意的是它不能有任何div或table後代。帶有後代和後代文本的XPath查詢()謂詞

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

所以這個查詢的唯一正確的結果將是:

/div/table/form/div 

我最好的嘗試看起來是這樣的:

//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)] 

但不返回正確的結果。

感謝您的幫助。

+0

好問題,+1。查看我的答案,可能是最短的解決方案。 :) – 2010-10-13 12:58:17

回答

32

不同的東西::)

//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] 

似乎比其他解決方案更短了很多,不是嗎? :)

翻譯成簡單的英文:對於文檔中包含字符串​​選擇它的始祖要麼是一個divtable任何文本節點。

這是更有效的,因爲只有一個文檔樹(而不是任何其他)的全掃描是必需的,相比descendent::(樹)掃描ancestor::*遍歷是很便宜的。

要驗證此解決方案 「確實有效」:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] "/> 
</xsl:template> 
</xsl:stylesheet> 

時所提供的XML文檔進行這種轉變:

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

想要的,正確的結果是生產

<div> 
    <span> 
     <p>abcdefg</p> 
    </span> 
</div> 

注意:沒有必要使用XSLT - 任何XPath 1.0主機(如DOM)都必須獲得相同的結果。

+1

感謝您的回覆,並感謝您的+1。我更喜歡這個答案的緊湊性,但是我無法讓它在我的測試中工作。另外兩個對這個問題的回覆對我有用。您的回覆中是否有拼寫錯誤?我不能聲稱瞭解所有這一切。[1]做什麼? 同樣,如果你有任何見解,爲什麼這個答案不適合我和其他人的工作,我會很感激。我會爲你的時間+1,但我是新來的這個網站,並沒有能力。謝謝。 – juan234 2010-10-14 00:37:16

+0

@ juan234:我在我的答案中加入了一些驗證碼,每個人都可以運行並驗證結果的正確性。此驗證顯示錶達的正確性 - 有*無*錯字。由於不同的原因,您可能會遇到問題:從使用不兼容的XPath 1.0引擎到代碼中的問題 - 查明需要查看代碼的原因。 '[1]'表示節點集的第一個節點,由緊接在[[1]右邊的表達式部分選擇 - 在反向軸上(例如'ancestor ::'它實際上表示最後一個節點按文件順序)。 – 2010-10-14 00:56:27

+0

我確信:) – juan234 2010-10-14 02:12:38

1

你可以嘗試:

//div[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] | 
//table[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] 

有何幫助?

1
//*[self::div|self::table] 
    [descendant::text()[contains(.,"abc")]] 
    [not(descendant::div|descendant::table)] 

contains(//text(), "abc")的問題是函數強制節點集採取第一個節點。