2016-05-24 113 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运作良好。这让后来的任何人都很难跟随该线程,而其他人很难看到发生了什么变化。询问一个新问题,并参考原文。 –