es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Demasiadas llamadas de función anidadas en XSLT, ¿recursividad por la cola?

Tengo una función recursiva en mi XSLT. Su objetivo es identificar “cadenas” de elementos, donde una cadena se define como una secuencia de elementos con start(n+1)=end(n), por ejemplo:


doo
doo
doo

doo
doo

Estoy usando la siguiente función recursiva:












Esto funciona bien siempre y cuando las secuencias de eventos no sean demasiado largas (generalmente no superan los 10 elementos). Sin embargo, si tienen una longitud por encima de cierto valor, la transformación arroja un error “Too many nested function calls in XSLT” (Demasiadas llamadas de función anidadas en XSLT). He leído que, para evitar esto, las funciones recursivas deben ser tail-recursive (recursión de cola). Sin embargo, no puedo ver por qué mi recursión no tendría esa propiedad. ¿Alguien ve qué podría estar mal aquí?

Estoy usando Saxon 9he como motor XSL.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    La función recursiva en el código XSLT proporcionado no parece ser recursividad final debido a que no tiene la propiedad de ser la expresión final que se evalúa en la función. La expresión final es una instrucción select en un bloque xsl:otherwise, no una llamada a la función en sí misma.

    Para hacer la función recursiva final, la expresión final debería llamar a la función con los nuevos valores de sus argumentos en lugar de devolver un valor calculado a partir de la llamada anterior. Esto se puede hacer usando una variable acumuladora para llevar un seguimiento del valor calculado por la llamada anterior, y pasándolo como argumento a la siguiente llamada.

    Aquí hay un ejemplo de cómo hacer la función recursiva final:

    <xsl:function name="exmaralda:last-endpoint-of-segment-chain" as="xs:string">
      <xsl:param name="event" as="element()"></xsl:param>
    
      <xsl:param name="acc" as="xs:string?" select="$event/@end"></xsl:param>
    
      <xsl:choose>
        <xsl:when test="not($event/following-sibling::event) or exmaralda:timeline-position($event/following-sibling::event[1]/@start) > exmaralda:timeline-position($event/@end)">
          <xsl:value-of select="$acc"></xsl:value-of>
        </xsl:when>
    
        <xsl:otherwise>
          <xsl:variable name="new-acc" select="$event/@end"></xsl:variable>
          <xsl:sequence select="exmaralda:last-endpoint-of-segment-chain($event/following-sibling::event[1], $new-acc)"></xsl:sequence>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:function>
    

    En esta versión de la función, la variable acumuladora acc se inicializa con el valor de $event/@end. En la llamada recursiva, este valor se pasa como argumento junto con el nuevo valor de $event/following-sibling::event[1].

    Cuando se alcanza la condición de terminación, el valor final de la variable acumuladora se produce como resultado de la función. Esto hace que la función sea recursiva final y evita el error “Demasiadas llamadas de función anidadas en XSLT”.

Comments are closed.