2010-10-13 17 views
15

Me gustaría construir una consulta XPath que devolverá un elemento "div" o "tabla", siempre que tenga un descendiente que contenga el texto "abc". La única advertencia es que no puede tener ningún descendiente div o de tabla.Consulta de XPath con predicados descendientes y descendientes de texto()

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

Así que el único resultado correcto de esta consulta sería:

/div/table/form/div 

Mi mejor intento es como la siguiente:

//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)] 

pero no devuelve el resultado correcto.

Gracias por su ayuda.

+0

Buena pregunta, +1. Vea mi respuesta para cuál es probablemente la solución más corta. :) –

Respuesta

32

Algo diferente: :)

//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] 

parece mucho más corta que las otras soluciones, ¿verdad? :)

traducido al Inglés sencillo: Para cualquier nodo de texto en el documento que contiene la cadena "abc" seleccione su primer antepasado que es o bien un div o una table.

Esto es más eficiente, ya que sólo un análisis completo de la estructura del documento (y no cualquier otra) que se requiere, y la ancestor::* recorrido es muy barato en comparación con un escaneo descendent:: (árbol).

Para comprobar que esta solución "realmente funciona":

<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="/"> 
    <xsl:copy-of select= 
    "//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] "/> 
</xsl:template> 
</xsl:stylesheet> 

cuando esta transformación se lleva a cabo en el documento XML proporcionado:

<div> 
    <table> 
    <form> 
     <div> 
     <span> 
      <p>abcdefg</p> 
     </span> 
     </div> 
     <table> 
     <span> 
      <p>123456</p> 
     </span> 
     </table> 
    </form> 
    </table> 
</div> 

el resultado deseado, correcta es producido:

<div> 
    <span> 
     <p>abcdefg</p> 
    </span> 
</div> 

Nota: No es necesario usar XSLT; cualquier host XPath 1.0, como DOM, debe obtener el mismo resultado.

+1

gracias por su respuesta y gracias por el +1. Prefiero la compacidad de esta respuesta, sin embargo, no puedo hacerlo funcionar en mis pruebas. Las otras dos respuestas a esta pregunta funcionan para mí. ¿Es posible que haya un error tipográfico en tu respuesta? No puedo decir que entiendo todo.¿Qué hace el [1]? De nuevo, si tiene alguna idea de por qué esta respuesta no funciona para mí y para los demás, se lo agradecería. Quisiera +1 por su tiempo, pero soy nuevo en este sitio y todavía no tengo la habilidad. Gracias. – juan234

+0

@ juan234: He agregado a mi respuesta un código de verificación que todos pueden ejecutar y verificar la corrección del resultado. Esta verificación muestra la corrección de la expresión: hay * no * typo. Puede tener problemas por diferentes motivos: desde el uso de un motor incompetente XPath 1.0 hasta problemas en su código, para identificar el motivo por el que es necesario ver su código. '[1]' significa el primer nodo del conjunto de nodos seleccionado por la parte de la expresión que está inmediatamente a la derecha de '[1]' - en ejes inversos (como 'ancestor ::' en realidad significa el último nodo en orden de documentos). –

+0

Estoy convencido :) – juan234

1

usted podría intentar:

//div[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] | 
//table[ 
    descendant::text()[contains(., "abc")] 
    and not(descendant::div or descendant::table) 
] 

ayuda eso?

1
//*[self::div|self::table] 
    [descendant::text()[contains(.,"abc")]] 
    [not(descendant::div|descendant::table)] 

El problema con contains(//text(), "abc") es que funciones de conversión conjuntos de nodos, teniendo el primer nodo.

Cuestiones relacionadas