2016-05-24 87 views
0

我想使用計數器遞增和遞減XSLT中的值。我能夠使用Apache Xalan實現這一點,但現在我想用Saxon實現相同的功能。使用Saxon,增加或減少XSLT中的全局變量

我對Xalan的XSLT腳本是這樣的:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:lxslt="http://xml.apache.org/xslt" 
       xmlns:result="http://www.example.com/results" 
       extension-element-prefixes="result"> 

    <lxslt:component prefix="result" functions="incr dcr"> 
     <lxslt:script lang="javascript"> 
      var count = 0; 
      function incr() { 
       count++; 
       return count; 
      } 

      function dcr() { 
       count--; 
       return count; 
      } 
     </lxslt:script> 
    </lxslt:component> 

    <xsl:template match="/"> 
     a)<xsl:value-of select="result:incr()"/> 
     b)<xsl:value-of select="result:incr()"/> 
     c)<xsl:value-of select="result:dcr()"/> 
    </xsl:template> 

</xsl:stylesheet> 

預期成果是:

a)1 
b)2 
c)1 

------------------------- my use case using saxon ------------------- 
This is my sample data.xml file. I want to transform this to html file. 

<entity> 
    <record>10</record> 
    <record>15</record> 
    <record>19</record> 
    <record>7</record> 
    <record>4</record> 
    <record>14</record> 
    <record>24</record> 
<entity> 

I want to implement a counter for line-number and want to increment the counter and print the line-number 
my expected outputs: 

case 1: If record values > 14, then my output should have line-number with value as. 
line-num value  
    1  15 
    2  19 
    3  24 

case 2 : If record values < 14, then my output should have line-number with value as. 
line-num value  
    1   10 
    2   7 
    3   4 

My other use case : 

<entity> 
    <record>10</record> 
    <record>15</record> 
    <record>19</record> 
    <record>7</record> 
    <record>20</record> 
    <record>14</record> 
    <record>24</record> 
    <entity> 
     <record>30</record> 
     <record>3</record> 
    </entity> 
</entity> 
<entity> 
    <record>5</record> 
    <record>17</record> 
    <record>19</record> 
    <record>6</record> 
    <record>70</record> 
    <record>9</record> 
    <record>35</record> 
    <entity> 
     <record>15</record> 
     <record>2</record> 
    </entity> 
</entity> 


This is my other use case, first <entity> record value > 15 and in second <entity> record value < 10, and my <entity> can grow bigger where i have to show only some record based on condition. 

line-num value 
    1  19 
    2  20 
    3  24 
    4  30 
    5  5 
    6  6 
    7  2 

回答

1

沒有辦法,據我知道撒克遜使用JavaScript。

如果你想使用撒克遜9(EE或PE)的分配和多變的變量,那麼你可以使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:saxon="http://saxon.sf.net/" 
    xmlns:mf="http://example.com/mf" 
    extension-element-prefixes="saxon" 
    exclude-result-prefixes="xs saxon mf" 
    version="2.0"> 

    <xsl:variable name="counter" as="xs:integer" select="0" saxon:assignable="yes"/> 

    <xsl:function name="mf:incr" as="xs:integer"> 
     <saxon:assign name="counter" select="$counter + 1"/> 
     <xsl:sequence select="$counter"/> 
    </xsl:function> 

    <xsl:function name="mf:decr" as="xs:integer"> 
     <saxon:assign name="counter" select="$counter - 1"/> 
     <xsl:sequence select="$counter"/> 
    </xsl:function> 

    <xsl:template match="/" name="main"> 
     a)<xsl:value-of select="mf:incr()"/> 
     b)<xsl:value-of select="mf:incr()"/> 
     c)<xsl:value-of select="mf:decr()"/> 
    </xsl:template> 

</xsl:stylesheet> 

見然而在試圖引進副作用http://saxonica.com/html/documentation/extensions/instructions/assign.html的警告和注意事項。你可能想編輯你的問題來解釋你的XML輸入和所需的輸出,以及爲什麼你認爲你需要這樣一個計數器變量,希望我們可以展示一個純粹的XSLT 2.0解決方案,而不是使用可分配的變量。

至於您的要求來處理和數量一定的輸入元件,樣式表

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" 
    version="2.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="entity"> 
     <root> 
      <xsl:apply-templates select="record[. > 14]"/> 
      <xsl:apply-templates select="record[. &lt; 14]"/> 
     </root> 
    </xsl:template> 

    <xsl:template match="record"> 
     <xsl:copy> 
      <line-num> 
       <xsl:value-of select="position()"/> 
      </line-num> 
      <value> 
       <xsl:value-of select="."/> 
      </value> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

當運行鍼對輸入

<entity> 
    <record>10</record> 
    <record>15</record> 
    <record>19</record> 
    <record>7</record> 
    <record>4</record> 
    <record>14</record> 
    <record>24</record> 
</entity> 

輸出

<root> 
    <record> 
     <line-num>1</line-num> 
     <value>15</value> 
    </record> 
    <record> 
     <line-num>2</line-num> 
     <value>19</value> 
    </record> 
    <record> 
     <line-num>3</line-num> 
     <value>24</value> 
    </record> 
    <record> 
     <line-num>1</line-num> 
     <value>10</value> 
    </record> 
    <record> 
     <line-num>2</line-num> 
     <value>7</value> 
    </record> 
    <record> 
     <line-num>3</line-num> 
     <value>4</value> 
    </record> 
</root> 

使用例如其它選項xsl:number count="entity[. &lt; 14]"。至於您的最新要求,我認爲只要您選擇要處理的元素,例如使用position(),您仍然可以處理該問題。例如,您可以使用position()。樣式表

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

    <xsl:output method="text"/> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="/root/entity[1]//record[. > 15], /root/entity[2]//record[. &lt; 10]"/> 
    </xsl:template> 

    <xsl:template match="record"> 
     <xsl:value-of select="concat(position(), ' ', ., '&#10;')"/> 
    </xsl:template> 

</xsl:stylesheet> 

當施加到輸入

<root> 
    <entity> 
     <record>10</record> 
     <record>15</record> 
     <record>19</record> 
     <record>7</record> 
     <record>20</record> 
     <record>14</record> 
     <record>24</record> 
     <entity> 
      <record>30</record> 
      <record>3</record> 
     </entity> 
    </entity> 
    <entity> 
     <record>5</record> 
     <record>17</record> 
     <record>19</record> 
     <record>6</record> 
     <record>70</record> 
     <record>9</record> 
     <record>35</record> 
     <entity> 
      <record>15</record> 
      <record>2</record> 
     </entity> 
    </entity> 
</root> 

輸出(與像撒克遜9的XSLT 2.0處理器)

1 19 
2 20 
3 24 
4 30 
5 5 
6 6 
7 9 
8 2 
+0

謝謝你的精神。 –

+0

我昨天經歷了撒克遜文檔,能夠想出它並嘗試了我的示例。 –

+0

「希望我們可以展示純粹的XSLT 2.0解決方案,而不是使用可分配的變量」,我希望控制計數器,以便用任何整數值遞增/遞減。 –

0

沒有JavaScript,使用撒克遜擴展指令。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:saxon="http://saxon.sf.net/" 
       extension-element-prefixes="saxon" 
       exclude-result-prefixes="saxon"> 
    <xsl:variable name="i" select="0" saxon:assignable="yes"/> 
    <xsl:template match="/"> 
     a) <xsl:value-of select="$i"/> 
      <saxon:assign name="i" select="$i+1"/> 
     b) <xsl:value-of select="$i"/> 
      <saxon:assign name="i" select="$i+2"/> 
     c) <xsl:value-of select="$i"/> 
      <saxon:assign name="i" select="$i+3"/> 
     d) <xsl:value-of select="$i"/> 
    </xsl:template> 
</xsl:stylesheet> 
+0

鏈接:http://www.saxonica.com/documentation9.5/extensions/instructions/assign.html –

1

(應對問題的擴大說明)

欣賞的關鍵的是,這個問題需要record元件的順序處理,在文檔順序。這意味着它無法通過與xsl:for-each或xsl:apply-templates處理器無關的方式實現,因爲這些不能保證按順序逐個處理元素(例如,最近的Saxon版本,將使用多線程並行處理元素,規範允許這樣做;這使得嘗試更新全局變量無效)。

按順序處理元素的經典方法是使用頭尾遞歸。編寫一個模板或函數,它將record元素的序列作爲參數,將當前行號作爲第二個參數。如果記錄列表非空,則(a)處理列表中的第一個record,並(b)遞歸地調用以處理列表的其餘部分,傳遞行號的新值。

第一次嘗試時用這種方式編寫代碼可能有點令人興奮,但它很快會自然而然地出現。

在XSLT 3.0中,有一個新的構造xsl:iterate,看起來更像一個傳統的循環:當你輸入xsl:iterate body時,你傳遞其參數的初始值,並且每次你繼續循環的下一次迭代您可以爲參數設置新的值。

+0

我有另一個用例,記錄元素可以是children.pleas提供你的想法。它可以在我的問題的「我的其他用例:」部分中找到。 –

+0

對不起,我不認爲當人們不斷增加新的補充問題時,SO運作良好。這讓後來的任何人都很難跟隨該線程,而其他人很難看到發生了什麼變化。詢問一個新問題,並參考原文。 –