2009-11-01 48 views
3

我不明白,從這個樣式表輸出:xsl:序列是否總是非空?

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
     <xsl:apply-templates select="root/sub"/> 
    </xsl:template> 

    <xsl:template match="sub"> 
     <xsl:variable name="seq"> 
      <xsl:sequence select="*" /> 
     </xsl:variable> 

     <xsl:message> 
      <xsl:value-of select="@id" /> 
      <xsl:text>: </xsl:text> 
      <xsl:value-of select="count($seq)" /> 
     </xsl:message> 
    </xsl:template> 
</xsl:stylesheet> 

當應用於以下XML:

<root> 
    <sub id="empty" /> 
    <sub id="one"><one/></sub> 
    <sub id="two"><one/><one/></sub> 
    <sub id="three"><one/><one/><one/></sub> 
</root> 

輸出,通過xsl:message元寫的,是:

empty: 1 
one: 1 
two: 1 
three: 1 

我的預期這一個代替:

empty: 0 
one: 1 
two: 2 
three: 3 

爲什麼count($seq)在這種情況下總是返回1?你將如何改變變量定義,以便我可以稍後測試它的空虛性? (簡單<xsl:variable name='seq' select='*' />將返回預期的答案,但不是一個選項...我想更改between變量在this template,並在稍後測試它爲空)。

回答

5

讓我試着回答你的問題的「爲什麼」部分。

如果你寫如下語句:

<xsl:variable name="x" select="*" /> 

變量$x包含當前節點的子節點的順序。 $x中沒有隱式父節點,因爲您使用的是select。現在考慮以下幾點:

<xsl:variable name="x"> 
    <content /> 
    <content /> 
</xsl:variable> 

其中變量$x包含一個節點的序列:中content父節點。在這裏,count($x)將永遠給你1。要獲得content元素的數量,您需要計算$x隱式根節點的子項:count($x/content)

作爲一個經驗法則,您可以記住:如果xsl:variable本身是一個空元素並且具有select屬性,則結果集將被分配給該變量。如果使用xsl:variable而沒有select屬性,則始終使用該變量創建一個隱式父項,並且該變量的內容爲其下的子項

這同樣適用於您的示例xsl:sequence作爲子xsl:variable。通過非空的xsl:variable可爲該序列創建一個隱式父親,這就是爲什麼如果您自己對該變量進行計數,則總是得到1的原因。

如果同時需要:一個內部xsl:variable語句的捆綁,但select屬性的行爲,可以通過使用解決此如下:

<xsl:variable name="x" select="$y/*" /> 

<xsl:variable name="y"> 
    <xsl:sequence select="foo" /> 
</xsl:variable> 

現在會產生預期的量count($x),但無論這是否真正有益或使您的代碼更清晰是有爭議的。

+0

非常感謝!爲了參考,這裏是鏈接到文檔的相關部分(如果我理解正確):http://www.w3.org/TR/xslt20/#temporary-trees – 2009-11-02 11:26:51

+1

是的,你確實瞭解它。該規範的這一部分顯示你隱含有一個'xsl:document'指令。它還指向我沒有提到的其他東西:如果您需要特定的輸出類型,則可以使用'as'屬性。 'xsl:variable'內部的序列必須可以轉換爲這種類型或發生錯誤。 – Abel 2009-11-02 11:35:35

2

您選擇的子節點,然後計算每個節點 - 所以它永遠是1.你需要計算的兒童,例如:

<xsl:value-of select="count($seq/*)" /> 

會給你,你的輸出期待。

+0

謝謝你回答。我不知道我的理解是什麼......然後(例如,當從samle輸入處理時)我的'seq'變量中存儲了什麼。我認爲這是兩個「一個」元素的序列。 – 2009-11-02 05:44:22

3

它的工作原理正如您所料,如果你要麼改變的變量聲明:

<xsl:variable name="seq" select="*"/> 

或聲明變量的使用類型「爲」屬性:

<xsl:variable name="seq" as="item()*"> 
     <xsl:sequence select="*" /> 
</xsl:variable> 

不指定任何類型信息通常會在XSLT 2.0中獲得令人驚訝的結果。如果您使用的撒克遜人,可以輸出如何撒克遜解釋使用說明擴展屬性的樣式表:

<xsl:template match="sub" saxon:explain="yes" xmlns:saxon="http://saxon.sf.net/"> 
    <xsl:variable name="seq"> 
     <xsl:sequence select="*" /> 
    </xsl:variable> 

    <xsl:message> 
     <xsl:value-of select="@id" /> 
     <xsl:text>: </xsl:text> 
     <xsl:value-of select="count($seq)" /> 
    </xsl:message> 
</xsl:template> 

正如你可以看到,撒克遜構建一個文檔節點出序列:

Optimized expression tree for template at line 6 in : 
        let $seq[refCount=1] as document-node() := 
         document-constructor 
         child::element() 
        return 
         message 
+0

謝謝'item()*'和'explain'提示(是的,我用撒克遜)。 – 2009-11-02 12:17:12