2010-09-30 12 views

Respuesta

27

En XPath 1.0 Una forma de hacer esto es mediante el uso del método Kayessian para intersección conjunto de nodos:

$ns1[count(.|$ns2) = count($ns2)] 

La expresión anterior selecciona exactamente los nodos que son parte tanto del conjunto de nodos $ns1 y el conjunto de nodos $ns2.

Para aplicar esto a la pregunta específica - digamos que tenemos que seleccionar todos los nodos entre el 2 y 3 h3 elemento en el siguiente documento XML:

<html> 
    <h3>Title T31</h3> 
    <a31/> 
    <b31/> 
    <h3>Title T32</h3> 
    <a32/> 
    <b32/> 
    <h3>Title T33</h3> 
    <a33/> 
    <b33/> 
    <h3>Title T34</h3> 
    <a34/> 
    <b34/> 
    <h3>Title T35</h3> 
</html> 

Tenemos que sustituir $ns1 con:

/*/h3[2]/following-sibling::node() 

y sustituir con $ns2:

/*/h3[3]/preceding-sibling::node() 

Por lo tanto, la expresión XPath completa es:

/*/h3[2]/following-sibling::node() 
      [count(.|/*/h3[3]/preceding-sibling::node()) 
      = 
       count(/*/h3[3]/preceding-sibling::node()) 
      ] 

Podemos comprobar que se trata de la expresión XPath correcta:

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

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "/*/h3[2]/following-sibling::node() 
      [count(.|/*/h3[3]/preceding-sibling::node()) 
      = 
       count(/*/h3[3]/preceding-sibling::node()) 
      ] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

Cuando esta transformación se aplica en el documento XML presentado anteriormente, el wante d, resultado correcto se produce:

<a32/> 

<b32/> 

II. XPath solución 2,0:

Utilice el intersect operador:

/*/h3[2]/following-sibling::node() 
intersect 
    /*/h3[3]/preceding-sibling::node() 
+1

+ 1 puede que el derecho siempre prevalezca. :-) – LarsH

+1

+1 para la solución más general y la invocación de la teoría de conjuntos –

+1

cosas agradables. funcionó línea un encanto – klumsy

1

Una solución más general - en XPath 2.0 - asumiendo que usted quiere nodos en todas las profundidades de árboles entre los dos elementos h3, que no necesariamente ser hermanos.

/path/to/first/h3/following::node()[. << /path/to/second/h3] 
7

otra solución XPath 1.0 cuando se sabe ambas marcas son el mismo elemento (este caso h3):

/html/body/h3[2]/following-sibling::node() 
          [not(self::h3)] 
          [count(preceding-sibling::h3)=2] 
+0

@ user3457812 ¡Gracias! ¡Esto funciona para mí! –

1

Basado en dimitre-novatchev excelente respuesta que puede hasta con la solución de seguimiento que en lugar de codificar [ 2] y [3] para los diferentes H3s solo le doy el contenido del encabezado del primer elemento.

//h3[text()="Main Page Section Heading"]/following-sibling::node() 
[ count(.|//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node()) = 
    count(//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node()) ] 

donde me quiero ir más lejos sin embargo es ser capaz de hacer frente a la situación cuando estoy buscando en el último H3, y tener todo después de que, en el caso anterior no puedo conseguir lo que sigue al último H3.

0

Hay otra gran solución genérica utilizando llaves, suponiendo que sus <h3> etiquetas tienen una propiedad única (por ejemplo, su texto o un atributo id):

<xsl:key name="siblings_of_h3" match="*[not(self::h3)]" use="preceding-sibling::h3[1]/text()"/> 

<xsl:template match="h3"> 
    <!-- now select all tags belonging to the current h3 --> 
    <xsl:apply-templates select="key('siblings_of_h3', text())"/> 
</xsl:template> 

Agrupa todos los tags por su anterior <h3>

Cuestiones relacionadas