Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xslt V1.0 - Simplest way to return multiple values from a subtemplate

I'm looking for an elegant way to return multiple values from one subtemplate.

why? - I have a subtemplate with a recursive loop that returns the max value of a node in an xml. I also need the min value and the total count of the nodes which I can simply get from the same subtemplate. I don't wonna loop 3 times, not really good for the performance :)

Solutions I found so far:

  • Create a string of the 3 values I need and get a substring of them.
  • ...

I'm using xsl v1.0

Thanks

like image 573
Stijn Heylen Avatar asked Jul 31 '11 14:07

Stijn Heylen


People also ask

Can we use multiple When in XSLT?

Yes we can have multiple conditions in the same <xsl:when> element.

How do you break out of a loop in XSLT?

There is no such a thing as break in an XSLT for-each loop. xsl:if/@test is pretty much all you can do. The other way would be to include this condition within the for-each/@select.

What is current group () in XSLT?

Returns the contents of the current group selected by xsl:for-each-group. Available in XSLT 2.0 and later versions. Available in all Saxon editions. current-group() ➔ item()*


1 Answers

It may not be convenient accessing each of many (say hundreds) results presented in a single string.

This is where the power of XML and XPath can be best seen and utilized: produce an XML tree as the result.

Here is an example:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/*">
      <xsl:call-template name="sequenceStatistics">
       <xsl:with-param name="pSeq" select="*"/>
      </xsl:call-template>
 </xsl:template>

 <xsl:template name="sequenceStatistics">
  <xsl:param name="pSeq"/>

  <xsl:variable name="vCount" select="count($pSeq)"/>

  <results>
   <count><xsl:value-of select="$vCount"/></count>
    <xsl:for-each select="$pSeq">
     <xsl:sort data-type="number"/>
     <xsl:choose>
       <xsl:when test="position() = 1">
         <min><xsl:value-of select="."/></min>
       </xsl:when>
       <xsl:when test="position() = $vCount">
         <max><xsl:value-of select="."/></max>
       </xsl:when>
     </xsl:choose>
    </xsl:for-each>
  </results>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

<nums>
  <num>7</num>
  <num>3</num>
  <num>9</num>
  <num>10</num>
  <num>4</num>
  <num>2</num>
  <num>5</num>
  <num>08</num>
  <num>6</num>
  <num>1</num>
</nums>

the wanted, correct result is produced:

<results>
   <count>10</count>
   <min>1</min>
   <max>10</max>
</results>

Do note:

  1. If the result is in the body of a variable, the variable type is RTF (Result Tree Fragment) and it must be converted to a regular tree using the xxx:node-set() function before the nodes of the result can be accessed individually. There is no such restriction in XPath 2.0 (XSLT 2.0).

  2. As this example shows, there is no need of recursion to produce the maximum and minimum of a sequence -- even in XSLT 1.0.

like image 155
Dimitre Novatchev Avatar answered Sep 19 '22 07:09

Dimitre Novatchev