2009-08-27 19 views
6

Tengo un bloque de XSLT que puede aplicarse varias veces a lo largo de una transformación. Pero quiero que realmente se ejecute solo la primera vez que se aplica, se debe omitir todos los tiempos secundarios. ¿Cómo hago esto?En XSLT, puedo ejecutar una plantilla solo una vez

A modo de ejemplo, este es el tipo de cosas que quiero hacer: En la hoja de estilo defino una variable global:

<xsl:variable name="run_once" select="0"/> 

entonces tengo una plantilla que se llama varias veces:

<xsl:template name="some_template"> 
    <xsl:if test="$run_once != 1"> 
     <xsl:variable name="run_once" select="1"/> 
     <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text> 
    </xsl:if> 
</xsl:template> 

Esto no funciona, por supuesto, porque las variables no se pueden cambiar, solo se sobrecargan. Por lo tanto, una vez que some_template sale $ run_once vuelve a ser 0 y el texto se aplica cada vez que se llama a la plantilla. ¿Hay algún tipo de funcionalidad ifdef u otro objeto global que pueda establecer?

Si usted está interesado en saber por qué quiero hacer esto, a continuación es una explicación más detallada de mi problema y la solución utilicé:

  • Mi entrada son datos en XML sin procesar, mi producción es una informe en formato WordML.
  • En la entrada tengo una serie de nodos (llamado theNode). Algunos, pero no todos, de estos nodos deben ser en la salida. El nodo debe mostrarse solo si XPATH hairyLogic es verdadero (hairyLogic es obviamente largo y complejo).
  • theNode también tienen un tipo (almacenado en un subnodo). En la entrada, todos theNode del mismo tipo serán siempre agrupados. En la salida , todos losNodo del mismo tipo deben agruparse bajo un encabezado específico para ese tipo (allí debe ser solo un encabezado para cada tipo ).

Esta es la solución que terminé usando:

... 
<xsl:apply-templates select="theNode[hairyLogic]"/> 
... 

<xsl:template match="theNode"> 
    <xsl:if test="count(preceding-sibling::theNode[type = current()/type and hairyLogic])=0"> 
     <xsl:choose> 
      <xsl:when test="type = 'TYPE1a' or type = 'TYPE1b'"> 
       <xsl:call-template name="TYPE1Heading"/> 
      </xsl:when> 
      <xsl:when test="type = 'TYPE2'"> 
       <xsl:call-template name="TYPE2Heading"/> 
      </xsl:when> 
     </xsl:choose> 
    </xsl:if> 
    ... 
</xsl:template> 

he elegido para usar plantillas con nombres de los encabezados, ya que contienen WordML básica que no depende de ningún dato en el XML de entrada.

No me gusta esta solución porque hairyLogic se repite y la sentencia if es intrincada y difícil de leer. ¿Tal vez tienes una mejor solución que no requiere variables mutables?

Respuesta

2

Sugeriría utilizar plantillas de coincidencia sobre plantillas con nombre porque es más, bueno, ¿cuál es el equivalente XSLT de pythonic? Xslt-y?Creo que encontrará que puede resolver problemas más fácilmente en esa metodología de procesamiento.

Si insiste en usar plantillas con nombre debido a algún requisito desconocido, puede encontrar que si refactoriza su lógica para facilitar la detección de la primera instancia, simplificará por completo su lógica.

¿Puede aclarar por qué no puede detectar cuándo se necesita la primera instancia? Probablemente podamos ayudar a crear una expresión xpath que le permita hacer lo que quiera. P.ej.

<xsl:template name="some_template"> 
    <xsl:variable name="EXPRESSION" select=".[somelogic='true']"/> 
    <xsl:if test="$EXPRESSION"> 
     <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text> 
    </xsl:if> 
</xsl:template> 

Desde XSLT es determinista - un efecto de ser completamente funcional como lo expresó Greg - (a menos que estés haciendo cosas extensión raro) puede decidir cuando el primer momento apropiado mediante la aplicación de la lógica a la entrada. Además, tiene acceso al nodo de contexto en la plantilla para que sepa de dónde se está llamando.

+0

"¿cuál es el equivalente XSLT de pythonic? Xslt-y?" - es "declarativo" –

+0

Sí, tengo restricciones que no detallé por completo (agregadas a la pregunta, si está interesado). Resolví el problema de la forma en que describes. No me gusta porque "Somelogic" es largo, desordenado, y ahora se repite varias veces. No sería tan malo si pudiera dictar cuando se analiza el código XPATH, como puedo en otros lenguajes funcionales. Entonces podría almacenar el bit malo de "somelogic" en una variable e insertarlo en mis expresiones cuando sea necesario. – oillio

2

Como XSLT es un lenguaje puramente funcional, hay no variables globales que puede establecer.

En su lugar, tendrá que elegir las circunstancias en las que llama a su plantilla some_template. Si solo desea llamarlo una vez, solo haga una llamada.

Cuestiones relacionadas