consulta XPath con el descendiente y el texto descendiente () predicados
-
29-09-2019 - |
Pregunta
Me gustaría construir una consulta XPath que devolverá un "div" o elemento de "mesa", con tal de que tiene un descendiente que contiene el texto "abc". La única advertencia es que no puede tener ningún div o tabla descendientes.
<div>
<table>
<form>
<div>
<span>
<p>abcdefg</p>
</span>
</div>
<table>
<span>
<p>123456</p>
</span>
</table>
</form>
</table>
</div>
Así que el resultado sólo correcto de esta consulta sería:
/div/table/form/div
Mi mejor apariencia intento algo como esto:
//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.
Solución
Algo diferente :)
//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1]
Parece mucho más corta que las otras soluciones, no es cierto? :)
Traducido al Inglés simple . Para cualquier nodo de texto en el documento que contiene la cadena de "abc"
seleccionar 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 otro) es necesaria, y el recorrido ancestor::*
es muy barato en comparación con un descendent::
(árbol) de exploración.
Para verificar 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 correcto querido se produce
<div>
<span>
<p>abcdefg</p>
</span>
</div>
Nota ??strong>:. No es necesario usar XSLT - cualquier XPath 1.0 anfitrión - como DOM, debe obtener el mismo resultado
Otros consejos
//*[self::div|self::table]
[descendant::text()[contains(.,"abc")]]
[not(descendant::div|descendant::table)]
El problema con contains(//text(), "abc")
es que las funciones echaron conjuntos de nodos teniendo el primer nodo.
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)
]
¿Le ayuda?