2015-07-20 41 views
0

似乎有不少類似的問題,但他們都沒有幫助我。我想重構下面這段XSLT:我可以用xslt中的計數器創建一個循環嗎?

<fo:table-cell xsl:use-attribute-sets="table-item-bordered"> 
    <fo:block> 
     <xsl:value-of select="/forms//instance[@versionNumber = '1']/content//textbox[@id = $id]/text()" /> 
    </fo:block> 
</fo:table-cell> 
<fo:table-cell xsl:use-attribute-sets="table-item-bordered"> 
    <fo:block> 
     <xsl:value-of select="/forms//instance[@versionNumber = '2']/content//textbox[@id = $id]/text()" /> 
    </fo:block> 
</fo:table-cell> 
<fo:table-cell xsl:use-attribute-sets="table-item-bordered"> 
    <fo:block> 
     <xsl:value-of select="/forms//instance[@versionNumber = '3']/content//textbox[@id = $id]/text()" /> 
    </fo:block> 
</fo:table-cell> 

請注意更改的versionNumber屬性。

XML源代碼看起來是這樣的:

<forms> 
    <instance versionNumber="3"> 
    <content> 
     <textbox id="1">THREE</textbox> 
    </content> 
    <previousVersions> 
     <instance versionNumber="1"> 
     <content> 
      <textbox id="1">ONE</textbox> 
     </content> 
     </instance> 
     <instance versionNumber="2"> 
     <content> 
      <textbox id="1">TWO</textbox> 
     </content> 
     </instance> 
    </previousVersions> 
    </instance> 
</forms> 

輸出的格式應該是這樣一個錶行:

+-----+-----+-------+ 
| ONE | TWO | THREE | 
+-----+-----+-------+ 

在代碼中,這將是這個樣子:

<table-cell>ONE</table-cell> 
<table-cell>TWO</table-cell> 
<table-cell>THREE</table-cell> 

這將很容易,而不使用循環計數器,但我總是需要3個單元格,無論有多少個版本。如果沒有與VERSIONNUMBER = 3沒有實例,該表需要是這樣的:

+-----+-----+-----+ 
| ONE | TWO |  | 
+-----+-----+-----+ 

或者在XML:

<table-cell>ONE</table-cell> 
<table-cell>TWO</table-cell> 
<table-cell></table-cell> 
+0

您不需要XSLT中的循環計數器。什麼是'$ instanceId'和'$ id'?同時顯示您的輸入的相關部分和您想要創建的輸出。也許這些變量不是必需的。 – Tomalak

+0

我已更新該問題。我寧願不使用循環計數器,因爲xslt是一種避免循環的函數式語言。在函數式語言中,我可能會在集合[1,2,3]上調用'map'並從那裏開始,是否有XSLT等同於這樣做? – Hannesh

+0

請將您的預期輸出**作爲代碼**發佈。 –

回答

0

受@ michael.hor257k的啓發,我最終沒有循環,但創建了一個命名模板並調用了3次。這足以滿足減少代碼重複並使其更清晰的需求:

<xsl:call-template name="table-cell"> 
    <xsl:with-param name="node" select="/forms//instance[@versionNumber = '1']/content//textbox[@id = $id]" /> 
</xsl:call-template> 
<xsl:call-template name="table-cell"> 
    <xsl:with-param name="node" select="/forms//instance[@versionNumber = '2']/content//textbox[@id = $id]" /> 
</xsl:call-template> 
<xsl:call-template name="table-cell"> 
    <xsl:with-param name="node" select="/forms//instance[@versionNumber = '3']/content//textbox[@id = $id]" /> 
</xsl:call-template> 

<xsl:template name="tableCell"> 
    <xsl:param name="node" /> 
    <fo:table-cell xsl:use-attribute-sets="table-item-bordered"> 
     <fo:block> 
      <xsl:value-of select="$node/text()" /> 
     </fo:block> 
    </fo:table-cell> 
</xsl:template> 
2

不循環,但額外的模板:

<xsl:template match="instance"> 
    <xsl:param name="id" /> 

    <fo:table-cell xsl:use-attribute-sets="table-item-bordered"> 
    <fo:block> 
     <xsl:value-of select="content//textbox[@id = $id]/text()" /> 
    </fo:block> 
    </fo:table-cell> 
</xsl:template> 

<!-- in another template... --> 
<xsl:apply-templates select="/forms//instance[@id = $instanceId and (@versionNumber &gt;= 1 and @versionNumber &lt;= 3)]"> 
    <xsl:with-param name="id" select="$id"/> 
    <xsl:sort select="@versionNumber" data-type="number"/> 
</xsl:apply-templates> 
+0

糟糕,錯過了這個表格單元格。謝謝,Tomalak。 –

+1

沒問題。當我看到你的回答彈出時,我正在寫同樣的東西。 :) – Tomalak

+0

謝謝你的回答魯道夫。對不起,我最初的問題並不清楚,但無論有多少個實例節點,即使只有1個或2個,我都需要確切地擁有3個表格單元格。 – Hannesh

1

我總是需要3個單元,不管有多少個版本。

只有三個單元格,你可以簡單地硬編碼它們,因爲你已經完成了。如果你不想這樣做,那麼你將使用一個循環,例如:

XSLT 1.0

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

<xsl:key name="instance" match="instance" use="@versionNumber" /> 

<xsl:template match="/forms"> 
    <root> 
     <xsl:call-template name="generate-cells"> 
      <xsl:with-param name="n" select="3" /> 
     </xsl:call-template> 
    </root> 
</xsl:template> 

<xsl:template name="generate-cells"> 
    <xsl:param name="n"/> 
    <xsl:if test="$n"> 
     <!-- recursive call --> 
     <xsl:call-template name="generate-cells"> 
      <xsl:with-param name="n" select="$n - 1" /> 
     </xsl:call-template> 
     <!-- current cell --> 
     <table-cell> 
      <xsl:value-of select="key('instance', $n)/content/textbox" /> 
     </table-cell> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

在功能性語言,我可以稱之爲「地圖'在集[1,2,3]和 去那裏,是否有XSLT等同於做?

在XSLT 2.0,你可以這樣做:

<xsl:template match="/forms"> 
    <xsl:variable name="forms" select="." /> 
    <root> 
     <xsl:for-each select="('1','2','3')"> 
      <table-cell> 
       <xsl:value-of select="key('instance', ., $forms)/content/textbox" /> 
      </table-cell> 
     </xsl:for-each> 
    </root> 
</xsl:template> 

甚至:

<xsl:for-each select="1 to 3"> 
     <table-cell> 
      <xsl:value-of select="key('instance', string(.), $forms)/content/textbox" /> 
     </table-cell> 
    </xsl:for-each> 
1

從評論:

我需要有確切3個表格單元格,無論有多少實例節點,即使只有1或2個。

那麼你可以使用一個小技巧和環比三個不相關的節點和濫用position()

<xsl:for-each select="//*[position() &lt;= 3]"> 
    <xsl:variable name="i" select="position()" /> 

    <fo:table-cell xsl:use-attribute-sets="table-item-bordered"> 
    <fo:block> 
     <xsl:value-of select="content/forms//instance[@versionNumber = $i]//textbox[@id = $id]/text()" /> 
    </fo:block> 
    </fo:table-cell> 
</xsl:for-each> 

或者你可以使用遞歸,這是XSLT一點更地道。它適用於重複的任意金額,但它也更長:

<xsl:template name="output-table-cell"> 
    <xsl:param name="i" /> 
    <xsl:param name="max" /> 

    <xsl:if test="$i &lt;= $max"> 
    <fo:table-cell xsl:use-attribute-sets="table-item-bordered"> 
     <fo:block> 
     <xsl:value-of select="content/forms//instance[@versionNumber = $i]//textbox[@id = $id]/text()" /> 
     </fo:block> 
    </fo:table-cell> 

    <!-- recursive step --> 
    <xsl:call-template name="output-table-cell"> 
     <xsl:with-param name="i" select="$i + 1" /> 
     <xsl:with-param name="max" select="$max" /> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

請注意,我假設$id在兩個片段的其他地方被定義。根據需要調整。

相關問題