2010-06-01 14 views
5

Soy nuevo en XPath, y por lo que he leído en algunos tutoriales sobre ejes, todavía me pregunto cómo implementarlos. No se están comportando del todo como yo esperaba. Estoy particularmente interesado en usar antepasados ​​y ejes descendientes.Ancestro XPath y descendiente en XSL copy-of

que tienen la siguiente estructura XML:

<file> 
    <criteria> 
     <root>ROOT</root> 
     <criterion>AAA</criterion> 
     <criterion>BBB</criterion> 
     <criterion>CCC</criterion> 
    </criteria> 
    <format> 
     <sort>BBB</sort> 
    </format> 
</file> 

Y tengo el siguiente XSL:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template> 

que no produce nada!

esperaba que producen:

<file> 
    <criteria> 
    </criteria> 
</file> 

¿Puede alguien explicar a los antepasados ​​y descendientes ejes a mí de una manera más útil que los tutoriales que he leído con anterioridad?

Gracias!

+0

Buena pregunta (+1). Vea mi respuesta para una explicación y una solución completa. –

Respuesta

5

Y tengo el siguiente XSL:

<xsl:template match="/"> 
    <xsl:copy-of select="ancestor::criterion/> 
</xsl:template> 

que no produce nada!

¡Como debería!

ancestor::criterion 

es una expresión relativa, lo que significa que se evalúa fuera del nodo actual (emparejado por la plantilla). Pero el nodo actual es el nodo de documento /.

Por lo tanto, lo anterior es equivalente a:

/ancestor::criterion 

Sin embargo, por definición, el nodo de documento / no tiene padres (y eso significa que no hay antepasados), por lo que esta expresión XPath no selecciona cualquier nodo.

esperaba que producen:

<file> 
    <criteria> 
    </criteria> 
</file> 

Lo que probablemente quería era:

//criterion/ancestor::* 

o

//*[descendant::criterion] 

Las dos últimas expresiones XPath son equivalentes y seleccionar todos los elementos que tienen un descendiente criterion.

Por último, para producir la salida que quería, aquí es una posible solución:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="root | criterion | format"/> 
</xsl:stylesheet> 

Cuando se aplica esta transformación en el documento XML proporcionado, la salida deseada se produce:

<file> 
<criteria> 
</criteria> 
</file> 
+0

Gracias por su respuesta. // criterio/ancestro :: * y // * [descendiente :: criterio] me dan resultados extraños, y aunque la solución totalmente codificada que proporcionó funciona y produce los resultados esperados, aún necesito una solución menos codificada (esto arriba) la solución requiere el conocimiento de la raíz y el formato ... pero puede haber otros que no conozco ...) Además, gracias por la explicación de los ejes descendente y ancestro :) – developer

+0

@iHeartGreek: ¿Por qué esperas una expresión XPath que seleccione nodos específicos para seleccionar otros nodos? En caso de que tenga otro problema, simplemente haga otra pregunta. No ha hecho la pregunta que no fue respondida. :) –

1

ancestor es para seleccionar los nodos que son más altos (más cerca de la raíz) en el documento XML. descendant es para seleccionar nodos que son inferiores (secundarios) en el documento XML.

En su ejemplo, ancestor::criterion selecciona nada, porque el nodo actual es / (es decir, la raíz del documento - <file> en este caso), como se indica por match="/". El nodo raíz no tiene ancestros, por lo que el eje ancestor no hace nada.

para que cada elemento de <criterion>, se debe utilizar el eje descendant:

<xsl:template match="/"> 
    <xsl:copy-of select="descendant::criterion"/> 
</xsl:template> 

o su acceso directo //:

<xsl:template match="/"> 
    <xsl:copy-of select="//criterion"/> 
</xsl:template> 

que devolverá el siguiente:

<criterion>AAA</criterion> 

Uso un bucle u otra plantilla que puede obtener los tres de ellos:

<xsl:template match="/"> 
    <file> 
    <xsl:apply-templates select="//criterion"/> 
    </file> 
</xsl:template> 
<xsl:template match="criterion"> 
    <xsl:copy-of select="."/> 
</xsl:template> 

Esto producirá el siguiente:

<file> 
    <criterion>AAA</criterion> 
    <criterion>BBB</criterion> 
    <criterion>CCC</criterion> 
</file> 

Si desea obtener el elemento <file>, también, que es un poco más complicado. XPath especifica los nodos y las copias simples no copiarán los elementos que contienen los elementos que seleccione. Puedo aclarar este punto más si todavía estás confundido.

+0

Usted dice que: ' ' devolverá el siguiente: ' AAA' Esto no es así. El resultado será: ' AAA acreditación CCC' –

+0

Sólo un punto, pero 'descendiente :: criterion' NO es equivalente a' // criterion'; este último encontrará todos los nodos criterio en todo el documento. El atajo correcto es '.// criterion'. – Flynn1179

Cuestiones relacionadas