2010-10-03 21 views
8

mirada a los dos ejemplos siguientes:XSLT, averiguar si es el último nodo hijo es un elemento específico

<foo>some text <bar/> and maybe some more</foo> 

y

<foo>some text <bar/> and a last <bar/></foo> 

nodos que contienen texto y bar elementos dentro del elemento foo. Ahora estoy en foo, y quiero saber si el último hijo es bar. El primer ejemplo debería ser falso, ya que hay texto después del bar, pero el segundo ejemplo debería ser verdadero.

¿Cómo puedo lograr esto con XSLT?

+0

Buena pregunta (+1). Vea mi respuesta para una solución corta y una sugerencia de estilo de escritura. :) –

Respuesta

12

Simplemente seleccione el último nodo del elemento <foo> y luego utilice el eje self para resolver el tipo de nodo.

/foo/node()[position()=last()]/self::bar 

Esta expresión XPath devuelve un conjunto vacío (lo que equivale a booleano falso) si el último nodo no es un elemento. Si desea obtener específicamente el valor true o false, ajuste esta expresión en la función XPath boolean(). Use self::* en lugar de self::bar para hacer coincidir cualquier elemento como el último nodo.

documento XML de entrada:

<root> 
    <foo>some text <bar/> and maybe some more</foo> 
    <foo>some text <bar/> and a last <bar/></foo> 
</root> 

documento XSLT ejemplo:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output method="text"/> 

<xsl:template match="foo"> 
    <xsl:choose> 
     <xsl:when test="node()[position()=last()]/self::bar"> 
      <xsl:text>bar element at the end&#10;</xsl:text> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:text>text at the end&#10;</xsl:text> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

</xsl:stylesheet> 

de salida de la hoja de estilo:

text at the end 
bar element at the end 
+1

También puede simplificar el predicado '/ foo/node() [last()]/self :: bar' –

+0

jasso: +1 Buena respuesta. También creo que el predicado '[last()]' es mejor –

7

Ahora estoy en foo, y quiere encontrar fuera si el l ast niño es un bar

Uso:

node()[last()][self::bar] 

El valor booleano de cualquier nodo-conjunto no vacío es true() y es false() para lo contrario. Puede usar la expresión anterior directamente (sin modificar) como el valor del atributo test de <xsl:if> o <xsl:when>.

mejor, use:

foo/node()[last()][self::bar] 

como el atributo de un match<xsl:template> - por lo tanto se escribe en estilo puro "empuje".

5

Actualización:Esta respuesta responde al requisito establecido en el título de la pregunta original, "averiguar si el último nodo hijo es un nodo de texto". Pero el cuerpo de la pregunta sugiere un requisito diferente, y parece que el último requerimiento fue el deseado por el PO.

Las dos respuestas anteriores prueban explícitamente si el último elemento secundario es un elemento bar, en lugar de probar directamente si se trata de un nodo de texto. Esto es correcto si foo contiene solo "nodos de texto mixto y elementos de barra" y nunca tiene cero hijos.

Pero es posible que desee probar directamente si el último hijo es un nodo de texto:

  1. Para facilitar la lectura de la lógica de estilo
  2. En caso de que el elemento contiene otros niños, además de los elementos y el texto: por ejemplo, comentarios o instrucciones de procesamiento
  3. En caso de que el elemento no tiene hijos

Tal vez usted sabe que los dos últimos no se producirá en su caso (pero a partir de su pregunta me imagino que podría nº 3). O tal vez lo creas, pero no estás seguro, o tal vez no lo has pensado. En cualquiera de los casos, es más seguro para probar directamente para lo que realmente quiere saber:

 test="node()[last()]/self::text()" 

Por lo tanto, sobre la base @ código de ejemplo de Dimitre y de entrada, la siguiente entrada XML:

<root> 
    <foo>some text <bar/> and maybe some more</foo> 
    <foo>some text <bar/> and a pi: <?foopi param=yes?></foo> 
    <foo>some text <bar/> and a comment: <!-- baz --></foo> 
    <foo>some text and an element: <bar /></foo> 
    <foo noChildren="true" /> 
</root> 

Con esta XSLT plantilla:

<xsl:template match="foo"> 
     <xsl:choose> 
     <xsl:when test="node()[last()]/self::text()"> 
      <xsl:text>text at the end;&#10;</xsl:text> 
     </xsl:when> 
     <xsl:when test="node()[last()]/self::*"> 
      <xsl:text>element at the end;&#10;</xsl:text> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:text>neither text nor element child at the end;&#10;</xsl:text> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

rendimientos:

text at the end; 
    neither text nor element child at the end; 
    neither text nor element child at the end; 
    element at the end; 
    neither text nor element child at the end; 
+2

Buena adición. Pero las respuestas anteriores no cambiaron las necesidades de OP, ya que parece sugerido por su primera oración. De la pregunta: 'quiero saber si el último niño es una barra'. –

+1

@Alejandro: buen punto. No me di cuenta de que el propio OP cambió los requisitos, entre el título y la frase que citó. Iba por el título. – LarsH

Cuestiones relacionadas