2009-12-11 128 views
4

我是XSLT的新手,但需要將其用於目前使用的CMS。我已經提出了一個問題,但我會嘗試描述它,而不會涉及底層CMS的太多信息。如果你需要更多的上下文來幫助我,我可以添加它。XSL:如何測試當前節點是否是另一個節點的後代

所以我想要做的就是測試如果我的XML的節點是特定節點的後代。

<xsl:if test="$currentNode::IsADescendantOf($someNode)"> 
Write this out. 
</xsl:if> 

任何想法的人?

感謝提前:)

回答

5

您應該使用UNION操作和節點集的大小比較:

<xsl:if test="count($someNode|$currentNode/ancestor::*) = count($currentNode/ancestor::*)"> 
Write this out. 
</xsl:if> 

如果$ someNode$ currentNode的祖先,$ someNode | $ currentNode /祖先:: *將返回與$ currentNode/ancestor :: *相同的節點集(node-set沒有任何雙重)。

如果不是,由於聯合,第一個節點集將比第二個節點集多一個節點。

+0

@Erlock:非常感謝您的幫助。工作過一種享受。 – 2009-12-13 23:38:48

1

查看 「祖先」 軸在XSL/XPath的參考

<xsl:if test="ancestor::*[. is $somenode]"> 

編輯:我跟你一起學習。看看這工作(我希望我有這個系統上可用我的XSL調試器:-)

+0

@Jim Garrison:感謝您的快速回復。這似乎是合理的,但我得到這個錯誤: System.Xml.Xsl.XslLoadException:期望一個節點測試,找到'$'。 – 2009-12-11 06:28:07

+0

你說得對,我的解決方案不完整。我沒有使用XSL ref,但基本思想是您需要使用祖先軸來選擇所有的祖先節點,然後根據節點相等性將其過濾爲$ somenode。 – 2009-12-11 06:32:29

+0

非常感謝。現在我得到「is-same-node()'是一個未知的XSLT函數」我會繼續討論它,但是讓我知道你是否有任何其他想法。 – 2009-12-11 06:42:09

0

後代檢查

,最好的辦法是使用後代:: *軸。

如果您有一段XML看起來像這樣並且想要匹配來自第一個<alpha>節點的後代<a>節點。

XML

<root> 
<!-- check for descendants of the following alpha node--> 
<alpha> 
    <!-- match the following node--> 
    <a>...</a> 
    <b>...</b> 
    <c>...</c> 
</alpha> 
<alpha> 
    <a>...</a> 
    <c>...</c> 
</alpha> 
</root> 

XSLT

<xsl:if test="/root/alpha[1]/descendant::a[. is current()]"> 

祖先檢查

這在大多數情況下,很可能工作。

<xsl:if test="ancestor::*[name() = $node]"> 

<xsl:variable name="node" select="name(//alpha)"/> 

或者你也可以使用產生-ID()如果你有多個節點以比較,需要確保它是一個節點的匹配,而不是名稱匹配。

<xsl:variable name="node" select="generate-id(//alpha[3])"/> 
<xsl:if test="ancestor::*[generate-id(.) = $node]"> 

is的比較操作者可以比較祖先時,因爲它需要的葉節點不IMO被使用,並且葉節點沒有後代。

但我建議使用descendant :: *軸,因爲它更具可讀性和靈活性。

2

一種便攜式(XPath 1.0和2.0)的解決辦法是:

<xsl:if test=" 
    $currentNode/ancestor::*[generate-id() = generate-id($someNode)] 
"> 
Write this out. 
</xsl:if> 

這走到祖先軸,並檢查在它的每一個元件。如果(且僅當)其中一個祖先的唯一ID與唯一ID爲$someNode匹配,則生成的節點集不爲空。

非空節點集計算爲true,所以條件滿足。

測試 - 找到所有<baz>這是<foo>後裔:

<xml> 
    <foo> 
    <bar> 
     <baz>Test 1</baz> 
    </bar> 
    </foo> 
    <baz>Test 2</baz> 
</xml> 

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:template match="/"> 
    <xsl:variable name="someNode" select="//foo[1]" /> 

    <!-- test each <baz> node if it has <foo> as a parent --> 
    <xsl:for-each select="//baz"> 
     <xsl:if test=" 
     ancestor::*[generate-id() = generate-id($someNode)] 
     "> 
     <xsl:copy-of select="." /> 
     </xsl:if> 

    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

結果

<baz>Test 1</baz> 

注意,如果你指的是實際 CURREN t節點,就像我在for-each中那樣,不需要單獨的$currentNode變量。默認情況下,所有XPath都與當前節點相關。

變體將是自上而下的方式。這是低效率的,但(可能是由幾個數量級):

<xsl:if test=" 
    $someNode[//*[generate-id() = generate-id($currentNode)]] 
"> 
Write this out. 
</xsl:if> 
1

答案很簡單,

所有你需要做的是:

<xsl:if test="count(ancestor::somenode)>0"> 

      .. 。然後添加其餘的

的邏輯是,如果節點是somenode的後代,那麼它將有一個或多個該節點。

相關問題