2011-07-20 28 views
10

Además de reescribir una gran cantidad de código XSLT (que no voy a hacer), ¿hay alguna manera de encontrar la posición de un elemento dentro de su elemento primario? cuando el contexto se establece arbitrariamente en otra cosa? He aquí un ejemplo:Encuentra la posición de un elemento dentro de su elemento primario con XSLT/XPath

<!-- Here are my records--> 
<xsl:for-each select="/path/to/record"> 
    <xsl:variable name="record" select="."/> 

    <!-- At this point, I could use position() --> 
    <!-- Set the context to the current record --> 
    <xsl:for-each select="$record"> 

    <!-- At this point, position() is meaningless because it's always 1 --> 
    <xsl:call-template name="SomeTemplate"/> 
    </xsl:for-each> 
</xsl:for-each> 


<!-- This template expects the current context being set to a record --> 
<xsl:template name="SomeTemplate"> 

    <!-- it does stuff with the record's fields --> 
    <xsl:value-of select="SomeRecordField"/> 

    <!-- How to access the record's position in /path/to or in any other path? --> 
</xsl:template> 

NOTA: Este es un ejemplo simplificado. Tengo varias limitaciones que me impiden implementar soluciones obvias, como pasar nuevos parámetros al SomeTemplate, etc. Realmente solo puedo modificar las partes internas de SomeTemplate.

NOTA: Estoy usando Xalan 2.7.1 con EXSLT. Entonces esos trucos están disponibles

¿Alguna idea?

Respuesta

24

Usted podría utilizar

<xsl:value-of select="count(preceding-sibling::record)" /> 

o incluso, de forma genérica,

<xsl:value-of select="count(preceding-sibling::*[name() = name(current())])" /> 

Por supuesto, este método no funcionará si se procesa una lista de nodos que no es uniforme, es decir:

<xsl:apply-templates select="here/foo|/somewhere/else/bar" /> 

la información de posición se pierde en tal caso, a menos que st de mineral en una variable y transmitir eso a la plantilla llamada:

<xsl:variable name="pos" select="position()" /> 
<xsl:for-each select="$record"> 
    <xsl:call-template name="SomeTemplate"> 
    <xsl:with-param name="pos" select="$pos" /> 
    </xsl:call-template> 
</xsl:for-each> 

pero obviamente eso significaría un cierto código de reescritura, que me di cuenta que desea evitar.


toque final: position() hace no os digo la posición del nodo dentro de su matriz. Le indica la posición del nodo actual relativo a la lista de nodos que está procesando en este momento.

Si solo procesa (es decir, "aplica plantillas para" o "repite") nodos dentro de un elemento primario, esto pasa a ser lo mismo. Si no lo haces, no lo es.

toque final # 2: Esta

<xsl:for-each select="/path/to/record"> 
    <xsl:variable name="record" select="."/> 
    <xsl:for-each select="$record"> 
    <xsl:call-template name="SomeTemplate"/> 
    </xsl:for-each> 
</xsl:for-each> 

es equivale a esto:

<xsl:for-each select="/path/to/record"> 
    <xsl:call-template name="SomeTemplate"/> 
</xsl:for-each> 

pero los últimos trabajos sin destruir el significado de position(). Llamar a una plantilla no cambia el contexto, por lo que .se se refieren al nodo correcto dentro de la plantilla llamada.

+2

¡Eres el hombre! Adapté tu sugerencia a '1 + count (previous-sibling :: *)' ¡y funcionó como un amuleto! –

+0

Acerca de su actualización: en el ejemplo del mundo real, los registros son siempre uniformes (aunque no siempre se llaman 'registro') ya que modelan una tabla. Por lo tanto, no existe un operador sindical de dos conjuntos de nodos XPath "incompatibles".La solución variable no funcionaría debido a la complejidad del código del mundo real –

+0

Gracias por los consejos adicionales sobre 'position()'. Como siempre estoy haciendo un bucle sobre elementos uniformes, en mi caso, la posición de bucle coincide con el índice del elemento dentro de su elemento primario. –

Cuestiones relacionadas