Pregunta

Yo soy el procesamiento de un archivo XML donde quiero contar el número de nodos, de modo que lo puedo usar como un ID como escribo nuevos nodos.

En el momento tengo una variable global llamada 'contador'.Yo soy capaz de acceder a ella dentro de una plantilla, pero no he encontrado una forma de manipulación dentro de una plantilla.

Aquí es una versión condensada de mi archivo XSLT:

<xsl:variable name="counter" select="1" as="xs:integer"/>

<xsl:template match="/"> 
   <xsl:for-each select="section">
      <xsl:call-template name="section"></xsl:call-template>
   </xsl:for-each>
</xsl:template>

<xsl:template name="section">

   <!-- Increment 'counter' here -->

   <span class="title" id="title-{$counter}"><xsl:value-of select="title"/></span>
</xsl:template>

Alguna sugerencia de cómo ir desde aquí?

¿Fue útil?

Solución

Otros ya han explicado cómo las variables son inmutables-que no hay instrucciones de asignación en XSLT (como puramente funcional de los lenguajes de programación en general).

Tengo una alternativa a las soluciones que se han propuesto hasta el momento.Evita la transmisión de parámetros (que es detallado y feo en XSLT, incluso he de admitirlo).

En XPath, usted puede simplemente contar el número de <section> los elementos que preceden a la actual:

<xsl:template name="section">
  <span class="title" id="title-{1 + count(preceding-sibling::section)}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

(Nota:el espacio en blanco de formato de código no aparecerán en el resultado, como en los espacios en blanco-sólo los nodos de texto se despojaron de la hoja de estilos de forma automática.Así que no te sientas obligado a poner las instrucciones en la misma línea.)

Una de las grandes ventajas de este enfoque (en oposición al uso de position()) es que es sólo dependen del nodo actual, no en la actual lista de nodos.Si usted cambió su procesamiento, de alguna manera (por ejemplo, por lo que <xsl:for-each> procesado no sólo secciones, pero algún otro elemento también), entonces el valor de position() ya no se corresponden necesariamente con la posición de <section> elementos en el documento.Por otro lado, si se utiliza count() como en el anterior, siempre se corresponde con la posición de cada uno de los <section> elemento.Este enfoque reduce el acoplamiento con otras partes de su código, que generalmente es una cosa muy buena.

Una alternativa para contar() sería el uso de la <xsl:number> de la instrucción.Es el comportamiento predeterminado será el número de todos como el nombre de los elementos en el mismo nivel, que pasa a ser lo que usted desea:

<xsl:template name="section">
  <xsl:variable name="count">
    <xsl:number/>
  </xsl:variable>
  <span class="title" id="title-{$count}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

Es un trade-off en el nivel de detalle que requiere un adicional de declaración de variable si usted todavía desea utilizar el valor del atributo de la plantilla de llaves), pero sólo un poco así, como también simplifica drásticamente su expresión XPath.

Hay más espacio para la mejora.Aunque hemos eliminado la dependencia de la actual lista de nodos, que todavía son dependientes del nodo actual.Que, de por sí, no es una mala cosa, pero no es inmediatamente claro a partir de la observación de la plantilla de lo que el nodo actual es.Todo lo que sabemos es que la plantilla se denomina "section";para saber con certeza lo que está siendo procesado, tenemos que buscar en otra parte, en nuestro código.Pero incluso eso no tiene que ser el caso.

Si alguna vez te sientes led para uso <xsl:for-each> y <xsl:call-template> juntos (como en tu ejemplo), un paso atrás y averiguar cómo utilizar <xsl:apply-templates> en su lugar.

<xsl:template match="/doc">
  <xsl:apply-templates select="section"/>
</xsl:template>

<xsl:template match="section">
  <xsl:variable name="count">
    <xsl:number/>
  </xsl:variable>
  <span class="title" id="title-{$count}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

No sólo es este enfoque menos detallado (<xsl:apply-templates/> reemplaza a la vez <xsl:for-each> y <xsl:call-template/>), pero también se convierte inmediatamente en claro cuál es el nodo actual es.Todo lo que tienes que hacer es mirar en el match atributo, y al instante saber que estás en el procesamiento de un <section> elemento y que <section> los elementos son lo que usted está contando.

Para una explicación sucinta de cómo la plantilla de reglas (es decir, <xsl:template> los elementos que tienen un match atributo) de trabajo, ver "¿Cómo XSLT Obras".

Otros consejos

Las variables XSLT no se pueden cambiar. Deberá pasar el valor de una plantilla a otra.

Si está utilizando XSLT 2.0, puede tener parámetros y usar túneles para propagar la variable a las plantillas correctas.

Su plantilla se verá así:

<xsl:template match="a">
<xsl:param name="count" select="0">
  <xsl:apply-templates>
     <xsl:with-param select="$count+1"/>
  </xsl:apply-templates>
</xsl:template>

Observe también el uso de generate-id () si desea crear identificadores.

Las variables en XSLT son inmutables, por lo que debe abordar el problema con eso en mente. Puede usar position() directamente:

<xsl:template match="/"> 
   <xsl:for-each select="section">
      <xsl:call-template name="section"/>
   </xsl:for-each>
</xsl:template>

<xsl:template name="section">
   <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span>
</xsl:template>

O de una manera más orientada a la plantilla:

<xsl:template match="/"> 
   <xsl:apply-templates select="section"/>
</xsl:template>

<xsl:template match="section">
   <span class="title" id="title-{position()}"><xsl:value-of select="title"/></span>
</xsl:template>

las variables tienen ámbito local y solo lectura en xslt.

Dependiendo de su procesador XSLT, es posible que pueda introducir funciones con script en su XLST. Por ejemplo, la biblioteca XML de Microsoft admite la inclusión de javascript. Consulte http://msdn.microsoft.com/en- us / library / aa970889 (VS.85) .aspx por ejemplo. Obviamente, esta táctica no funcionará si planea implementar / ejecutar XSLT en navegadores de clientes públicos; tiene que hacerlo un procesador XSLT específico.

Puede usar la función position () para hacer lo que quiera. Se vería algo así.

<xsl:template match="/">
  <xsl:for-each select="section">
    <xsl:call-template name="section">
      <xsl:with-param name="counter" select="{position()}"/>
    </xsl:call-template>
  </xsl:for-each>
</xsl:template>

<xsl:template name="section">
  <xsl:param name="counter"/>
  <span class="title" id="title-{$counter}">
    <xsl:value-of select="title"/>
  </span>
</xsl:template>

No lo he intentado yo mismo, pero puedes intentar pasar un parámetro a la plantilla. En su primera plantilla, configura el parámetro para contar () (¿o actual () quizás?) Dentro de la instrucción for-each y luego pasa ese valor a su & Quot; sección & Quot; plantilla.

Aquí encontrará más información sobre pasar parámetros a plantillas

Usar <xsl:variable name="RowNum" select="count(./preceding-sibling::*)" /> y $RowNum como un valor incremental.

Por ejemplo: <xsl:template name="ME-homeTiles" match="Row[@Style='ME-homeTiles']" mode="itemstyle"> <xsl:variable name="RowNum" select="count(./preceding-sibling::*)" /> ...<a href="{$SafeLinkUrl}" class="tile{$RowNum}"><img ....></a>

Esto creará clases para el enlace con valores tile1, tile2, tile3, etc. ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top