2017-10-07 75 views
2

根據this SO問題應該可以使用XPath表達式中的參數match。但是,如果在同一個模板中使用xsl:templatexsl:param,它似乎不起作用。在XSLT 2.0的匹配XPath表達式中不可能使用模板參數?

我的XML文件看起來如下

<?xml version="1.0" encoding="UTF-8"?> 
<myRoot> 
    <myNode myAttribute="3"> 
     <myChildAttribute myChildAttribute="a" /> 
    </myNode> 
    <myNode myAttribute="2"> 
     <myChildAttribute myChildAttribute="b" /> 
    </myNode> 
    <myNode myAttribute="1" /> 
</myRoot> 

和喜歡我的XSL文件。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" encoding="UTF-8"/> 

    <xsl:template match="myRoot"> 
     <xsl:apply-templates select="myNode"> 
      <xsl:sort select="@myAttribute" /> 
      <xsl:with-param name="myParam" select="max(myNode/@myAttribute)" /> 
     </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="myNode[node() and @myAttribute = $myParam]"> 
     <xsl:param name="myParam" /> 
      <xsl:for-each select="myChildAttribute"> 
INSERT INTO a(b) VALUES ('<xsl:value-of select="@myChildAttribute" />'); 
      </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

不幸的是,當與SAXON 9HE運行,出現以下錯誤

XPST0008: Variable myParam has not been declared (or its declaration is not in scope) 

結束是沒可能使用模板的參數在相同模板匹配XPath表達式! ?

回答

3

不可能在相同模板的 match-XPath表達式中使用模板參數!?

不,模板的匹配表達式中的任何變量/參數必須在範圍中(定義/可見),當選擇模板執行時。

因爲模板是XSLT指令(在全局級別定義),所以在範圍內(它們可以看到)中唯一的變量/參數是全局級變量/參數。

模板參數只有在選擇模板執行後纔會傳遞給模板 - 而不是在此之前。這意味着當執行模板選擇過程時,此參數的值不存在。因此,如果要在執行過程的模板選擇中使用非全局表達式,則需要在相應的xsl:apply-templates指令的select屬性中提供該表達式,在該指令中可以評估該表達式 - 而不是在match模板的屬性,其中無法評估此表達式。

要明確這一點,下面的代碼糾正問題所提供的代碼

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
     <xsl:output method="text" encoding="UTF-8"/> 

     <xsl:template match="myRoot"> 
      <xsl:apply-templates select="myNode[@myAttribute = max(../myNode/@myAttribute)]"> 
       <xsl:sort select="@myAttribute" /> 
      </xsl:apply-templates> 
     </xsl:template> 

    <xsl:template match="myNode[node()]"> 
      <xsl:for-each select="myChildAttribute"> 
INSERT INTO a(b) VALUES ('<xsl:value-of select="@myChildAttribute" />'); 
      </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

當這種變換所提供的XML文檔應用:

<myRoot> 
    <myNode myAttribute="3"> 
     <myChildAttribute myChildAttribute="a" /> 
    </myNode> 
    <myNode myAttribute="2"> 
     <myChildAttribute myChildAttribute="b" /> 
    </myNode> 
    <myNode myAttribute="1" /> 
</myRoot> 

沒有錯誤產生,這是轉換的輸出(我不能說「正確的輸出」,因爲沒有要求h已被定義,因此它們不能被驗證。我對此代碼有所保留:例如,xsl:apply-templates<xsl:sort>孩子的使用是沒有意義的,因爲它會對相等(max())值進行排序並對相同值序列進行排序產生相同的序列):

INSERT INTO a(b) VALUES ('a'); 
+1

謝謝Dimitre!現在,我很清楚。 'xsl:sort'只是來自以前版本轉換的剩餘部分。感謝提示,我將刪除它。 – Jagger

2

我不認爲這會奏效。該參數在您定義的模板內有效。但是,匹配表達式實際上並不是模板的一部分。當myParam尚未定義時,必須從外部進行評估。

您必須將max(myNode/@ myAttribute)的過濾移至apply-templates調用的select表達式。