2010-06-01 54 views
5

我是XPath的新手,從我在某些關於軸的教程中閱讀的內容中,我仍然想知道如何實現它們。他們的行爲不像我預料的那樣。我對使用祖先和後代軸特別感興趣。XPath祖先和後代在XSL副本

我有以下XML結構:

<file> 
    <criteria> 
     <root>ROOT</root> 
     <criterion>AAA</criterion> 
     <criterion>BBB</criterion> 
     <criterion>CCC</criterion> 
    </criteria> 
    <format> 
     <sort>BBB</sort> 
    </format> 
</file> 

而且我有以下XSL:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template> 

產生什麼!

我希望它產生:

<file> 
    <criteria> 
    </criteria> 
</file> 

有人能比教程我以前看過一個更加有用的方式解釋祖先和後代軸給我嗎?

謝謝!

+0

好問題(+1)。請參閱我的回答以獲取解釋和完整解決方案。 – 2010-06-01 21:47:14

回答

5

而且我有以下XSL:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template> 

產生什麼!

因爲它應該!

ancestor::criterion 

是一個相對錶達,這意味着它被評估關閉當前節點(由模板匹配的)。但是當前節點是文檔節點/

所以,上述等效於:

/ancestor::criterion 

然而,通過定義文檔節點/不具有父母(這意味着沒有祖先),所以這XPath表達式不選擇任何節點。

我希望它產生:

<file> 
    <criteria> 
    </criteria> 
</file> 

什麼你可能想要的是:

//criterion/ancestor::* 

//*[descendant::criterion] 

最後兩個XPath表達式是等價的,選擇所有具有criterion後代的元素。

最後,產生你想要的輸出,這裏是一個可能的解決方案:

<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="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="root | criterion | format"/> 
</xsl:stylesheet> 

當這種變換所提供的XML文檔應用,想要的輸出產生

<file> 
<criteria> 
</criteria> 
</file> 
+0

謝謝你的迴應。 // criterion/ancestor :: *和// * [descendant :: criterion]會給我帶來奇怪的結果,雖然您提供的完全編碼的解決方案確實可以工作併產生預期的結果,但我仍然需要一個不太硬編碼的解決方案解決方案需要根和格式的知識..但可能有其他人我不知道..) 此外,感謝您的解釋的後代和祖先軸:) – developer 2010-06-02 14:48:51

+0

@iHeartGreek:你爲什麼期望一個XPath表達式,選擇特定的節點來選擇其他節點?如果您有其他問題,請提出另一個問題。你沒有問過沒有回答的問題。 :) – 2010-06-02 16:30:24

1

ancestor用於選擇XML文檔中較高(更接近根)的節點。 descendant用於選擇XML文檔中較低(子級)的節點。

在您的例子,ancestor::criterion選擇任何操作,因爲當前節點是/(意味着文檔的根 - 在這種情況下<file>),通過match="/"所示。根節點沒有祖先,所以ancestor軸不做任何事情。

讓每一個<criterion>元素,你應該使用descendant軸:

<xsl:template match="/"> 
    <xsl:copy-of select="descendant::criterion"/> 
</xsl:template> 

或其快捷//

<xsl:template match="/"> 
    <xsl:copy-of select="//criterion"/> 
</xsl:template> 

這將返回以下內容:

<criterion>AAA</criterion> 

使用一個循環或另一個模板,你可以得到所有三個其中:

<xsl:template match="/"> 
    <file> 
    <xsl:apply-templates select="//criterion"/> 
    </file> 
</xsl:template> 
<xsl:template match="criterion"> 
    <xsl:copy-of select="."/> 
</xsl:template> 

這將產生如下:

<file> 
    <criterion>AAA</criterion> 
    <criterion>BBB</criterion> 
    <criterion>CCC</criterion> 
</file> 

如果你想獲得<file>元素,太,這是一個比較複雜。 XPath指定節點和簡單副本不會複製包含所選元素的元素。如果你仍然感到困惑,我可以澄清這一點。

+0

你說: '的 ' 將返回以下內容: ' AAA' 事實並非如此。其結果將是: ' AAA BBB CCC' – 2010-06-01 21:46:20

+0

只是一個點,而是'後裔:: criterion'並不等同於'// criterion';後者將在整個文檔中找到所有標準節點。正確的捷徑是'.// criterion'。 – Flynn1179 2010-06-03 09:13:29