miércoles, 4 de julio de 2012

La línea descendant de XPath

Dado un nodo de contexto, la línea descendant selecciona los hijos de ese nodo y además los nietos, los biznietos, etc.

La línea descendant no selecciona los atributos de los nodos y tampoco la nombre de espacio.

Para la selección utilizo tanto pasos de localización simplificados como sin simplificar. La notación no simplificada es más intuitiva, pero es más pesada.

Documento XML de ejemplo

          <?xml version="1.0" encoding="UTF-8"?>

<!-- New document created with EditiX at Wed Jul 04 18:40:54 BST 2012 -->

<X>
 <A>
  <F>
   <T/>
   <K/>
   <P/>
   <Q/>
  </F>
  <F>
   <E/>
  </F>
 </A>
 <B>
  <G>
   <E/>
   <G/>
   <Y/>
  </G>
  <J>
   <E/>
  </J>
  <R>
   <A/>
   <w/>
   <Q/>
   <B/>
  </R>
 </B>
 <C>
  <F>
   <Z/>
   <N/>
   <M/>
  </F>
 </C>
</X>
        

En el siguiente ejemplo debes notar que el nodo de contexto es doble, ya que hay dos nodos con la misma etiqueta, lo cual no es muy académico, pero pese a ello el analizador lo resuelve; por tanto, fíjate que el resultado da como resultado la descendencia de dos nodos.

Ejemplo nº1, línea descendant de XPath

Hoja de transformación:

          <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:template match="/">
  <xsl:copy-of select="X/A/F/descendant::node()"/>
 </xsl:template>
</xsl:stylesheet>

Salida:

<T/> <K/> <P/> <Q/> <E/>

Recordemos que existe una notación simplificada de XPath. En el siguiente ejemplo simplificamos mediante (//) la línea descendant. Nota que el resultado es la descendencia de todos los nodos con etiqueta F,

Ejemplo nº2, notación simplificada de la línea descendant

Hoja de transformación:

          <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:template match="/">
  <xsl:copy-of select="//F/descendant::node()"/>
 </xsl:template>
</xsl:styleshee>

Salida:

<T/> <K/> <P/> <Q/> <E/> <Z/> <N/> <M/>

lunes, 2 de julio de 2012

Nodo test en XPath

El nodo test es uno de los componente del paso de localización XPath y junto con la línea va definir cuáles son los nodos que vamos a coger del árbol XML que analizamos.
Además de tener una línea XPath, cada paso de localización tiene un nodo test. El nodo test tiene dos maneras excluyentes de elegir los nodos: por el nombre del nodo (el nombre de la etiqueta XML) o por la clase de nodo.

Las clases de nodos son las siguientes:

  • comment()
  • node()
  • processing-instruction()
  • text()

Recordemos que utilizamos una línea XPath dentro de un paso de localización para indicar al analizador que nos estamos refiriendo a un determinado número de nodos del árbol XML que tratamos. Dicho de otra manera: cada una de las líneas supone un conjunto de nodos que están predefinidos en la especificación y que siempre son los mismos tomoando como referencia el nodo de contexto.

Por ejemplo, si escribimos el paso de localización

child::isla

usamos una línea (la línea child) y un el nombre de nodo "isla", que corresponderá a una etiqueta del documento XML.


Ejemplo nº1 Nodo test con nombre de nodo y con clase de nodo

Entrada:

<?xml version="1.0" encoding="UTF-8"?>

<!-- New document created with EditiX at Mon Jul 02 17:41:45 BST 2012 -->

<isla nombre="La Palma" capital="Santa Cruz de la Palma">
 <gentilicio_masculino>
 palmero
 <!--Por supuesto, el gentilicio femenino será palmera-->
 </gentilicio_masculino>
 <superficie>708,32</superficie>
 <sitio nombre="Tazacorte">
  <gentilicio_masculino>bagañete</gentilicio_masculino>
  <superficie>11,36</superficie>
 </sitio>
 <sitio nombre="Villa de Mazo">
  <gentilicio_masculino>mazuco</gentilicio_masculino>
  <superficie>71,17</superficie>
 </sitio>
 <sitio nombre="Santa Cruz de la Palma">
  <gentilicio_masculino>santacrucero</gentilicio_masculino>
  <superficie> 43,38</superficie>
 </sitio>
</isla>

Hoja de transformación:

<?xml version="1.0" encoding="UTF-8"?>

<!-- New document created with EditiX at Sun Jun 17 18:55:04 BST 2012 -->

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:template match="/">
  <!--Utilizamos en el paso de localización final como nodo test el nombre del elemento-->
  <xsl:element name="gentilicio_1">
   <xsl:value-of select="child::isla/child::gentilicio_masculino"/>
  </xsl:element>
  <!--Utilizamos en el paso de localización final como nodo test el nombre de la clase de nodo texto.
  En este caso el nodo gentilicio_masculino tiene dos hijos: un nodo texto y un nodo comentario-->
  <xsl:element name="gentilicio_2">
   <xsl:value-of select="child::isla/child::gentilicio_masculino/child::text()"/>
  </xsl:element>
  <!--Utilizamos en el paso de localización final como nodo test el nombre de la clase de nodo comentario.-->
  <xsl:element name="comentario">
   <xsl:value-of select="child::isla/child::gentilicio_masculino/child::comment()"/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

Salida:

<gentilicio_1>palmero</gentilicio_1>

<gentilicio_2>palmero</gentilicio_2>

<comentario>Por supuesto, el gentilicio femenino será palmera</comentario>