2011-07-03 40 views
4

我想處理有哪幾種不同的狀態組像XSLT和臨時文件

<root> 
<childgroup>16</childgroup> 
<setstate>init</setstate> 
<child1>...</child1> 
<child2>...</child2> 
<setstate>process<setstate> 
<child2>...</child2> 
<child3>...</child3> 
..... 
<childgroup>17</childgroup> 
... 

一個XML文件我需要的其實是得到類似

<childgroup no="16"> 
    <state statename="init"> 
    <child1>...</child1> 
    <child2>...</child2> 
    </state> 
    <state statename="process"> 
    <child2>...</child2> 
    <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="17"> 
... 

我已經做了簡單的一部分並將「chgrpno」屬性和stateid屬性添加到所有子項(它使所有元素的副本,但是子組和副本的狀態,將屬性添加到這兩個元素中)

<xsl:template match="/"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:template> 

這樣做的結果是,所有的孩子都有屬性,所以我可以在下一關重新組合它們,並且州有數字,所以我以後可以做同樣的事情。但是,試圖跟隨M.Kay的例子有「臨時文件」當我嘗試做

<xsl:variable name="nmb"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:variable> 

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

那麼它只是返回原來的我,我在第一遍的所有變化都沒有了。那麼我在這裏做錯了什麼?

我明確地使用了XSLT 1.0,而不是XSLT 2.0。

(編輯:當然我命名變量,忘記複製它在這裏)。

+0

問得好,+1。查看我的答案,瞭解XSLT 1.0中必需的RTF轉換爲臨時樹的解釋。此外,還提供了兩遍XSLT 1.0處理的完整代碼示例。 –

回答

3

以下是一個示例,說明如何在一步中使用XSLT 1.0進行分組;樣式表

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:output indent="yes"/> 

    <xsl:key name="k1" match="root/*[not(self::childgroup)]" 
    use="generate-id(preceding-sibling::childgroup[1])"/> 

    <xsl:key name="k2" match="root/*[not(self::childgroup) and not(self::setstate)]" 
    use="concat(generate-id(preceding-sibling::childgroup[1]), '|', generate-id(preceding-sibling::setstate[1]))"/> 

    <xsl:template match="root"> 
    <xsl:copy> 
     <xsl:apply-templates select="childgroup"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="childgroup"> 
    <childgroup no="{.}"> 
     <xsl:apply-templates select="key('k1', generate-id())[self::setstate]"/> 
    </childgroup> 
    </xsl:template> 

    <xsl:template match="setstate"> 
    <state statename="{.}"> 
     <xsl:copy-of select="key('k2', concat(generate-id(preceding-sibling::childgroup[1]), '|', generate-id()))"/> 
    </state> 
    </xsl:template> 

</xsl:stylesheet> 

將輸入樣本

<root> 
    <childgroup>16</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>17</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
</root> 

<root> 
    <childgroup no="16"> 
     <state statename="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
     </state> 
     <state statename="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
     </state> 
    </childgroup> 
    <childgroup no="17"> 
     <state statename="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
     </state> 
     <state statename="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
     </state> 
    </childgroup> 
</root> 
+0

+1一個很好的答案。 –

0

你應該命名你的變量,然後你可以複製它

<xsl:variable name="rtf1"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:variable> 

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

使用XSLT 1.0,如果你不想給變量的內容,而不是與複製和拷貝要處理它與應用的模板,那麼你需要的擴展功能就像exsl:node-set例如

<xsl:variable name="rtf1"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:variable> 

<xsl:template match="/"> 
    <xsl:apply-templates select="exsl:node-set($rtf1)/node()"/> 
</xsl:template> 
+0

這正是我的問題:就像你給的代碼是在書凱的臨時結果,它不工作 - 我要是<應用模板>裏面的我獲得理想的結果,但我這樣做的變量中時,像你這樣的建議,我在「麻木」模式所做的修改都將丟失。 – Konstantin

+0

考慮後最小但完整和真實樣本使我們能夠重現問題。 –

2

在多遍處理的關鍵一點與XSLT 1.0是包含第一個的結果的變量pass並不包含一個XML文檔(樹)。

該變量包含RTF(結果樹片段)。 RTF僅在XSLT 1.0中定義。只能使用RTF完成的操作是<xsl:copy-of><xsl:value-of>或將它作爲參數傳遞 - 任何將RTF視爲字符串的東西。

根據定義,任何嘗試使用帶有位置測試的XPath表達式的RTF內部 - 都必須失敗。

解決方法是使用擴展函數,通常命名爲xxx:node-set()(但Xalan使用名稱「nodeset」no dash),其中"xxx:"前綴綁定到特定的實現定義XSLT處理器。正如Martin Honnen所建議的,爲了達到某種程度的可移植性,每當由特定的XSLT處理器實現時,都應該嘗試使用EXSLT common:nodeset()擴展。

這裏是XSLT 1.0兩遍的處理的例子:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="http://exslt.org/common" 
exclude-result-prefixes="ext"> 
<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="num[not(. mod 2)]"/> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfPass1"> 
    <xsl:apply-templates/> 
    </xsl:variable> 

    <nums> 
    <xsl:apply-templates mode="pass2" 
     select="ext:node-set($vrtfPass1)/*"/> 
    </nums> 
</xsl:template> 

<xsl:template match="num" mode="pass2"> 
<x> 
    <xsl:apply-templates/> 
</x> 
</xsl:template> 
</xsl:stylesheet> 

當該XML文檔上施加:

<nums> 
    <num>01</num> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <num>05</num> 
    <num>06</num> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 

這種轉變在第一遍產生過濾樹,其中只有num元件具有奇數值都存在。然後第二次通過重命名每num元件x。最終的結果是:

<nums> 
    <x>01</x> 
    <x>03</x> 
    <x>05</x> 
    <x>07</x> 
    <x>09</x> 
</nums> 
1

另一個(單通)可能的方法(不是說簡單的一個)是:

  • 複製節點集作爲變量
  • 使用變量引用的基礎上同一組遞歸
的相鄰兄弟姐妹交叉節點集的謂詞
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output indent="yes"/> 
    <xsl:template match="text()"/> 

    <xsl:template match="*" mode="childx"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="childgroup"> 
     <xsl:variable name="fw" select="following-sibling::*"/> 
     <childgroup no="{.}"> 
      <xsl:variable name="fwrw" 
       select="$fw[self::childgroup][1] 
       /preceding-sibling::*"/> 
      <xsl:apply-templates select="following-sibling::*[ 
       count(. | $fwrw) = count($fwrw) 
       or count($fwrw)=0] 
       [self::setstate] " mode="setstate"/> 
     </childgroup> 
    </xsl:template> 

    <xsl:template match="setstate" mode="setstate"> 
     <xsl:variable name="fw" select="following-sibling::*"/> 
     <state name="{.}"> 
      <xsl:variable name="fwrw" 
       select="$fw[ self::setstate or self::childgroup ][1]/ 
       preceding-sibling::*"/> 
      <xsl:apply-templates select="following-sibling::*[ 
       count(. | $fwrw) = count($fwrw) 
       or count($fwrw) = 0]" mode="childx"/> 
     </state> 
    </xsl:template> 
</xsl:stylesheet> 

當下面的XML應用:

<root> 
    <childgroup>16</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>17</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>18</childgroup> 
    <childgroup>19</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>20</childgroup> 
</root> 

產地:

<childgroup no="16"> 
    <state name="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
    </state> 
    <state name="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="17"> 
    <state name="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
    </state> 
    <state name="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="18"/> 
<childgroup no="19"> 
    <state name="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
    </state> 
    <state name="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="20"/>