Frage zu xpath
Thomas Mell
- xml
Hallo,
folgender XML-Node:
<node att="a b c" />
Ist es möglich mit xpath diesen Node über die Angabe eines Teils des Attributwertes zu finden ? Also z.B. "Gib mir alle Elemente die im Attribut 'att' den Wert 'b' enthalten, quasi wie es bei CSS mit ~= möglich ist.
Grüße
Thomas
Hallo Thomas,
Ist es möglich mit xpath diesen Node über die Angabe eines Teils des Attributwertes zu finden?
Ja, mit der XPath-Funktion contains().
Also z.B. "Gib mir alle Elemente die im Attribut 'att' den Wert 'b' enthalten, quasi wie es bei CSS mit ~= möglich ist.
//*[contains(@att, "b")]
Erklärt:
• //*
selektiert alle Elementknoten.
• //*[foo]
selektiert alle Elementknoten bei denen die der Ausdruck „foo“ True zurückgibt. Nennt man auch Prädikat
• contains(@att, "b")
ist so eine Bedingung. Die Funktion liefert True zurück, wenn der String "b" im Wert des Attributes "att" enthalten ist, ansonsten false.
Dieser Ausdruck liefert ausgeführt gegenüber der Forumshauptdatei z.B. alle li-Elemente zurück, deren class-Attribut den String "visited" enthält ...
//li[contains(@att, "visited")]
... selektiert also alle gelesenen Threads. Praktisch, da so ein class-Attribut in HTML ja auch andere Klassen enthalten kann ("no-archive" und so), es in XPath 1.0 meines Wissens aber keine Möglichkeiten gibt, auf der Ebene der Klassen zu arbeiten.
Mit XPath 2.0 kann man da wohl mehr machen, vermute ich, da man dort auch mit XML Schema Datentypen operieren kann; ein token-basiertes Attribut hätte dann den Datentyp xsd:NMTOKENS. Allerdings kenne ich mich im Lande von XPath 2.0 und XQuery 1.0 so gut wie kaum aus und habe auch die Vermutung, das wäre komplizierter, als ein einfache Substring-Überprüfung wie oben. Aber vielleicht kann Thomas J.S. da mehr sagen. ;)
Tim
Hallo Gunnar,
//li[contains(@att, "visited")]
Tztztz: //li[contains(@class, "visited")]
Tim
Hello out there!
•
contains(@att, "b")
ist so eine Bedingung. Die Funktion liefert True zurück, wenn der String "b" im Wert des Attributes "att" enthalten ist
Aber auch bei "xxb". Das könnte ungewollt sein.
See ya up the road,
Gunnar (der ohne [tm]) ;-)
Hi Tim
genau dafür brauche ich es - alle Elemente mit einer Klasse x finden.
Wie Du schon sagst, es können mehrere Klassen vorkommen und contains findet ja auch Klassen in denen die gesuchte Zeichenfolge "reinpasst".
Dafür habe ich aber ne Lösung gefunden - nicht schön aber es funktioniert:
//*[
@class = 'b'
or contains(@class, ' b ')
or starts-with(@class, 'b ')
or substring(@class, string-length(@class) - string-length('b')) = ' b'
]
Finden in den folgenden Beispielen richtigerweise die ersten 4:
<g class="b"/>
<g class="b c"/>
<g class="a b c"/>
<g class="a b"/>
<g class="aber"/>
<g class="ab er"/>
<g class="a ber"/>
<g class="baer"/>
<g class=" baer"/>
<g class="bergab"/>
<g class="bergab "/>
In .NET gibt es sogar Ergebnisse wenn sich zwischen den Klassen andere Whitespaces befinden (tab, Zeilenumbrüche). Diese werden dann Hexadezimal (0d und 0a) oder unverändert (tab) ausgegeben.
Ist das eine Eigenart von .NET oder ist das bei xpath so ?
Vielen Dank und Grüße
Thomas
Hi Tim
genau dafür brauche ich es - alle Elemente mit einer Klasse x finden.
Wie Du schon sagst, es können mehrere Klassen vorkommen und contains findet ja auch Klassen in denen die gesuchte Zeichenfolge "reinpasst".
Dafür habe ich aber ne Lösung gefunden - nicht schön aber es funktioniert:
Falls die "Klassen" durch Leerzeichen getrennt sind:
contains(@attribut, ' gesuchtezeichefloge ')
Grüße
Thomas
Hello out there!
Falls die "Klassen" durch Leerzeichen getrennt sind:
contains(@attribut, ' gesuchtezeichefloge ')
Hm, findest du damit <foo class="gesuchtezeichefloge nichtgesuchte dieauchnicht">
?
See ya up the road,
Gunnar
Hallo,
Falls die "Klassen" durch Leerzeichen getrennt sind:
contains(@attribut, ' gesuchtezeichefloge ')Hm, findest du damit
<foo class="gesuchtezeichefloge nichtgesuchte dieauchnicht">
?
Wieso stellst du eine Frage, auf die du die Antwort kennst?
Grüße
Thomas
Tach,
Wieso stellst du eine Frage, auf die du die Antwort kennst?
wegen der Griechen vermutlich.
mfg
Woodfighter
Hallo Thomas,
Dafür habe ich aber ne Lösung gefunden - nicht schön aber es funktioniert:
Das reicht ja auch. ;) Und es ist eine recht praktikable Lösung für das Problem.
In .NET gibt es sogar Ergebnisse wenn sich zwischen den Klassen andere Whitespaces befinden (tab, Zeilenumbrüche). Diese werden dann Hexadezimal (0d und 0a) oder unverändert (tab) ausgegeben. Ist das eine Eigenart von .NET oder ist das bei xpath so ?
Ich hab keine Ahnung von .NETs XPath-Implementierung, aber für mich scheint das so, als sei das ein Resultat der in XML eingebauten Attribut-Normalisierung.
Tim
Tach Tim,
Mit XPath 2.0 kann man da wohl mehr machen, ...
Ja, dazu mal ein Ansatz mit der neuen XPath-Funktion fn:matches():
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:template match="root">
<xsl:variable name="className" select="'b'"/>
<xsl:value-of select="for $a in //@* return fn:matches($a,fn:concat('(^|\s)',$className,'(\s|$)'))"/>
</xsl:template>
</xsl:stylesheet>
Bezogen auf diese XML-Instanz:
<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
<node att="a b c" />
<node att="a c b" />
<node att="a bb c" />
<node att="b c d" />
<node att="ab cb" />
</root>
ergibt sich: true true false true false ('b' wird bei true also jeweils gefunden).
Man liest sich,
svg4you