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

  <!-- Esta hoja de estilo contiene un ejemplo de suma de un conjunto
       de nodos, en la que se requiere una transformación previa de
       cada nodo antes de que pueda ser interpretado como un número
       sumable.

       Este no es un ejercicio trivial, puesto que la función sum() no
       puede ser usada.  Esto es porque la transformación de los
       sumandos necesariamente generaría un "result tree fragment",
       pero sum() solo se puede aplicar a un "nodeset".  A falta de
       una función para convertir un "result tree fragment" en un
       "nodeset", la suma debe realizarse manualmente.

       En este ejemplo, la suma se realiza mediante el named-template
       recursivo "suma".  Este template acepta como parámetro una
       colección de nodos, y recurre sobre sí mismo, eliminando el
       primer elemento de la colección en cada recursión.  La
       recursión se detiene cuando no quedan más elementos.  En este
       punto, la recursión regresa, sumando un acumulador
       (inicializado en cero) a cada uno de los elementos que fueron
       eliminándose en cada paso.  El resultado final es la suma
       deseada.

       Dentro de "suma" se invoca al template "numerifica" toda vez
       que se requiere realizar una operación de suma.  Este template
       puede ser arbitrariamente complejo: su función es generar un
       número a partir de cada uno de los nodos a sumar.

       Probado con xsltproc.

       Comentarios, dudas, crítica constructiva y de la otra:
       César Rincón <crincon@et.com.mx> -->

  <xs:output method="xml"/>

  <xs:template match="cuentas">
    <resultado>
      <xs:call-template name="suma">
        <xs:with-param name="items" select="saldo"/>
      </xs:call-template>
    </resultado>
  </xs:template>

  <xs:template name="suma">
    <xs:param name="items"/>
    <xs:param name="result" select="0"/>
    <xs:choose>
      <xs:when test="$items">
        <xs:variable name="num">
          <xs:call-template name="numerifica">
            <xs:with-param name="texto" select="$items[1]"/>
          </xs:call-template>
        </xs:variable>
        <xs:call-template name="suma">
          <xs:with-param name="items" select="$items[position() > 1]"/>
          <xs:with-param name="result" select="$result + number($num)"/>
        </xs:call-template>
      </xs:when>
      <xs:otherwise>
        <xs:value-of select="$result"/>
      </xs:otherwise>
    </xs:choose>
  </xs:template>

  <xs:template name="numerifica">
    <xs:param name="texto"/>
    <xs:choose>
      <xs:when test="substring($texto, string-length($texto), 1) = '+'">
        <xs:value-of select="substring($texto, 1, string-length($texto) - 1)"/>
      </xs:when>
      <xs:when test="substring($texto, string-length($texto), 1) = '-'">
        <xs:value-of
            select="concat('-', substring($texto, 1, string-length($texto) - 1))"/>
      </xs:when>
      <xs:otherwise>
        <xs:value-of select="$texto"/>
      </xs:otherwise>
    </xs:choose>
  </xs:template>

</xs:stylesheet>
