Chong Lip Phang
Chong Lip Phang

Reputation: 9279

How to use xsl:stream, xsl:accumulator, xs:fork from XSLT 3.0?

I am reading the W3C documentation for XSLT 3.0 here. I wonder how to use these elements:

(1) xsl:decimal-format
(2) xsl:stream
(3) xsl:accumulator
(4) xsl:accumulator-rule
(5) xsl:fork

Apparently these are some of the less used elements. As the examples given there are limited, answers provided here will benefit future learners of XSLT. Could someone please demonstrate how to use them?

I know that is a lot to answer. So I will upvote any correct partial answer, in the hope that it will be useful to others.

Upvotes: 2

Views: 2118

Answers (2)

Michael Kay
Michael Kay

Reputation: 163458

xsl:decimal-format has been in the spec since version 1.0; the other elements you cite are new in version 3.0, and are all associated with streaming (that is, the ability to process a source document "on the fly", without loading the whole tree in memory).

<xsl:stream href="in.xml">
   ...do something...
</xsl:stream>

has essentially the same effect as

<xsl:for-each select="doc('in.xml')">
   ...do something...
</xsl:for-each>

except that the "do something" is streamed (which means it must conform to the rules for streamability). For example, if you want to find out the average salary of a large number of employees, you could do

<xsl:stream href="in.xml">
   <result><xsl:value-of select="avg(//employee/@salary)"/></result>
</xsl:stream>

What if you want to compute the min and max salary during a single streaming pass of the input document? xsl:fork and accumulators both provide solutions to this problem. xsl:fork allows you to specify two or more computations that happen during the same pass, effectively in parallel:

<xsl:stream href="in.xml">
   <result>
     <xsl:fork>
        <xsl:sequence>
           <min><xsl:value-of select="min(//employee/@salary)"/></min>
        </xsl:sequence>
        <xsl:sequence>
           <max><xsl:value-of select="max(//employee/@salary)"/></max>
        </xsl:sequence>
     </xsl:fork>
   </result>
</xsl:stream>

xsl:accumulator allows you to define processing that occurs effectively as a side-effect of reading the document:

<xsl:accumulator name="min-salary" initial-value="10000000">
  <xsl:accumulator-rule match="employee" 
      select="if (@salary lt $value) then @salary else $value"/>
</xsl:accumulator>

and you can then at any point in processing read off the minimum salary so far by calling accumulator-before('min-salary').

Upvotes: 5

matthias_h
matthias_h

Reputation: 11416

<xsl:decimal-format>
Found a good example here: MSDN xsl:decimal-format

Example reduced: Declaring <xsl:decimal-format> in the XSL

<xsl:decimal-format name="example" decimal-separator="." grouping-separator=","  
 infinity="INFINITY" minus-sign="-" NaN="Not a Number" percent="%"
 per-mille="m" zero-digit="0" digit="#" pattern-separator=";" />

Using it with <xsl:format-number>

<xsl:value-of select="format-number(1 div 0, '###,###.00', 'example')"/>  

Output: INFINITY
Reference: http://www.w3.org/TR/2013/WD-xslt-30-20131212/#dt-decimal-format
Full working demo tested on http://exselt.net/demo:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="decimalformat.xsl"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="html"/>   
<xsl:decimal-format name="example" decimal-separator="." grouping-separator=","
  infinity="INFINITY" minus-sign="-" NaN="Not a Number" percent="%"
  per-mille="m" zero-digit="0" digit="#" pattern-separator=";" /> 
<xsl:template match="/">
  <html>
    <head></head>
    <body>
        <xsl:value-of select="format-number(1 div 0, '###,###.00', 'example')"/>  
    </body>
  </html>
</xsl:template>

Upvotes: 2

Related Questions