sibling online following example attribute xml xslt xpath

online - xpath xml



¿Cómo puedo generar una lista separada por comas con XSLT/XPath? (7)

Teniendo en cuenta estos datos XML:

<root> <item>apple</item> <item>orange</item> <item>banana</item> </root>

Puedo usar este marcado XSLT:

... <xsl:for-each select="root/item"> <xsl:value-of select="."/>, </xsl:for-each> ...

para obtener este resultado:

manzana, naranja, plátano,

pero ¿cómo puedo producir una lista donde la última coma no está presente? Supongo que se puede hacer haciendo algo como:

... <xsl:for-each select="root/item"> <xsl:value-of select="."/> <xsl:if test="...">,</xsl:if> </xsl:for-each> ...

pero, ¿cuál debería ser la expresión de prueba?

Necesito alguna forma de averiguar cuánto tiempo dura la lista y dónde estoy actualmente en la lista, o, alternativamente, si actualmente estoy procesando el último elemento de la lista (lo que significa que no me importa cuánto tiempo o qué la posición actual es).


Esta es la forma en que lo conseguí trabajando para mí. Probé esto en tu lista:

<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" /> <xsl:template match="root"> <xsl:call-template name="comma-join"><xsl:with-param name="list" select="item"/></xsl:call-template> </xsl:template> <xsl:template name="comma-join"> <xsl:param name="list" /> <xsl:for-each select="$list"> <xsl:value-of select="." /> <xsl:if test="position() != last()"> <xsl:text>, </xsl:text> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet>


Este es un patrón bastante común:

<xsl:for-each select="*"> <xsl:value-of select="."/> <xsl:if test="position() != last()"> <xsl:text>,</xsl:text> </xsl:if> </xsl:for-each>


Para una opción XSLT 2.0, puede usar el atributo separator en xsl:value-of .

Este xsl:value-of :

<xsl:value-of select="/root/item" separator=", "/>

produciría esta salida:

apple, orange, banana

También podría usar más que solo una coma para un separador. Por ejemplo, esto:

<xsl:text>''</xsl:text> <xsl:value-of select="/root/item" separator="'', ''"/> <xsl:text>''</xsl:text>

Produciría el siguiente resultado:

''apple'', ''orange'', ''banana''

Otra opción de XSLT 2.0 es string-join() ...

<xsl:value-of select="string-join(/*/item,'', '')"/>


Robert dio la respuesta classis not(position() = last()) . Esto requiere que procese toda la lista de nodos actual para obtener el tamaño de contexto, y en documentos de entrada grandes, esto podría hacer que la conversión consuma más memoria. Por lo tanto, normalmente invierto la prueba para ser lo primero

<xsl:for-each select="*"> <xsl:if test="not(position() = 1)>, </xsl:if> <xsl:value-of select="."/> </xsl:for-each>


Un simple one-liner XPath 1.0 :

concat(., substring('','', 2 - (position() != last())))

Ponlo en esta transformación:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/*"> <xsl:for-each select="*"> <xsl:value-of select= "concat(., substring('','', 2 - (position() != last())))" /> </xsl:for-each> </xsl:template> </xsl:stylesheet>

y aplicarlo al documento XML :

<root> <item>apple</item> <item>orange</item> <item>banana</item> </root>

para obtener el resultado deseado:

apple,orange,banana

EDITAR:

Aquí hay un comentario de Robert Rossney a esta respuesta:

Es un código bastante opaco para que un humano lo lea. Requiere que conozca dos cosas no obvias sobre XSLT: 1) qué hace la función de subcadena si su índice está fuera de rango y 2) que los valores lógicos se pueden convertir implícitamente a valores numéricos.

y aquí está mi respuesta :

Chicos, nunca se avergüencen de aprender algo nuevo. De hecho, esto es de lo que se trata , ¿verdad? :)


Observe las position() , count() y last() ; por ejemplo, test="position() &lt; last()" .


<xsl:if test="following-sibling::*">,</xsl:if>

o (quizás más eficiente, pero tendría que probar):

<xsl:for-each select="*[1]"> <xsl:value-of select="."/> <xsl:for-each select="following-sibling::*"> <xsl:value-of select="concat('','',.)"/> </xsl:for-each> </xsl:for-each>