XPath-Abfrage mit Nachkommen und Nachkommen text () Prädikate
-
29-09-2019 - |
Frage
Ich mag eine XPath-Abfrage erstellen, die eine „div“ oder „Tabelle“ Element zurückkehren, solange es einen Nachkommen mit dem Text „abc“ hat. Die einzige Einschränkung ist, dass es keine div oder Tisch Nachkommen haben kann.
<div>
<table>
<form>
<div>
<span>
<p>abcdefg</p>
</span>
</div>
<table>
<span>
<p>123456</p>
</span>
</table>
</form>
</table>
</div>
So ist das einzige richtige Ergebnis dieser Abfrage wäre:
/div/table/form/div
Mein bester Versuch sieht etwa so aus:
//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)]
aber nicht zurück das korrekte Ergebnis.
Danke für Ihre Hilfe.
Lösung
Etwas anderes :)
//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1]
Es scheint, viel kürzer als die anderen Lösungen, nicht wahr? :)
übersetzte auf einfaches Englisch :. Für jeden Textknoten in dem Dokument, das die Zeichenfolge "abc"
wählen Sie die ersten Vorfahren enthält, die entweder ein div
oder ein table
Das ist effizienter , da nur ein Scan des Dokumentbaums (und nicht irgendeine andere) erforderlich ist, und der ancestor::*
Traversal ist sehr günstig im Vergleich zu einem descendent::
(Baum) Scan.
Um sicherzustellen, dass diese Lösung "wirklich funktioniert":
<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>
, wenn diese Transformation auf dem mitgelieferten XML-Dokument ausgeführt wird, :
<div>
<table>
<form>
<div>
<span>
<p>abcdefg</p>
</span>
</div>
<table>
<span>
<p>123456</p>
</span>
</table>
</form>
</table>
</div>
das wollte, ist richtige Ergebnis erzeugt :
<div>
<span>
<p>abcdefg</p>
</span>
</div>
Hinweis . Es ist nicht notwendig, XSLT zu verwenden - jeder XPath 1.0 Host - wie DOM, muß das gleiche Ergebnis erhalten
Andere Tipps
//*[self::div|self::table]
[descendant::text()[contains(.,"abc")]]
[not(descendant::div|descendant::table)]
Das Problem ist, dass contains(//text(), "abc")
Funktionen Knotenmengen gegossen den ersten Knoten nehmen.
Sie könnten versuchen:
//div[
descendant::text()[contains(., "abc")]
and not(descendant::div or descendant::table)
] |
//table[
descendant::text()[contains(., "abc")]
and not(descendant::div or descendant::table)
]
tut diese Hilfe?