Signatur
Beschreibung
Die Methode evaluate() der Schnittstelle XPathEvaluator wertet einen XPath-1.0-Ausdruck relativ zu einem Kontextknoten aus. Je nach angefordertem Ergebnistyp bekommst du eine Zahl, eine Zeichenkette, einen Wahrheitswert, einen einzelnen Knoten oder eine Knotenmenge (als Iterator oder Snapshot) zurück, jeweils verpackt in ein XPathResult-Objekt.
Nützlich ist XPath immer dann, wenn CSS-Selektoren nicht ausreichen: etwa beim Suchen nach Textinhalten (//button[contains(., "Speichern")]), beim Navigieren zu Eltern- oder Geschwisterknoten (.., following-sibling::), bei Berechnungen wie count() oder sum() und beim Durchsuchen von XML-Dokumenten, die per DOMParser oder fetch geladen wurden.
Funktional ist die Methode identisch mit Document.prototype.evaluate(). Ein eigenständiger new XPathEvaluator() lohnt sich vor allem, wenn du Ausdrücke mit createExpression() vorkompilieren willst oder unabhängig von einem bestimmten Dokument arbeitest.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $expression Pflicht | string | Der auszuwertende XPath-Ausdruck (XPath 1.0). | |
| $contextNode Pflicht | Node | Knoten, relativ zu dem der Ausdruck ausgewertet wird, meist document oder ein Element. |
|
| $resolver | XPathNSResolver|Function|null | null | Löst Namensraum-Präfixe im Ausdruck zu URIs auf. Entweder eine Funktion (prefix) => uri, ein Objekt mit lookupNamespaceURI() oder null, wenn keine Präfixe verwendet werden. |
| $type | number | XPathResult.ANY_TYPE (0) | Gewünschter Ergebnistyp, z. B. XPathResult.NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, ORDERED_NODE_SNAPSHOT_TYPE, FIRST_ORDERED_NODE_TYPE oder ORDERED_NODE_ITERATOR_TYPE. |
| $result | XPathResult|null | null | Ein vorhandenes XPathResult zur Wiederverwendung. In der Praxis fast immer null. |
Rückgabewert
XPathResult-Objekt. Welche Eigenschaft gilt (numberValue, stringValue, booleanValue, singleNodeValue, snapshotItem(), iterateNext()), hängt von resultType ab.Beispiele
Button anhand seines Textes finden
const evaluator = new XPathEvaluator();
const result = evaluator.evaluate(
'//button[normalize-space(.)="Speichern"]',
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
const button = result.singleNodeValue;
console.log(button ? button.outerHTML : 'Kein Button gefunden');
Alle Links als Snapshot einsammeln
const evaluator = new XPathEvaluator();
const snapshot = evaluator.evaluate(
'//a[starts-with(@href, "https://")]',
document,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
);
const urls = [];
for (let i = 0; i < snapshot.snapshotLength; i++) {
urls.push(snapshot.snapshotItem(i).href);
}
console.log(`${urls.length} externe Links`, urls);
Berechnung in einem geparsten XML-Dokument
const xml = `<bestellung>
<posten preis="19.90"/>
<posten preis="5.10"/>
<posten preis="25.00"/>
</bestellung>`;
const doc = new DOMParser().parseFromString(xml, 'application/xml');
const evaluator = new XPathEvaluator();
const summe = evaluator.evaluate(
'sum(/bestellung/posten/@preis)',
doc,
null,
XPathResult.NUMBER_TYPE,
null
).numberValue;
const anzahl = evaluator.evaluate('count(//posten)', doc, null, XPathResult.NUMBER_TYPE, null).numberValue;
console.log(`${anzahl} Posten, Summe: ${summe.toFixed(2)} €`);
Namensräume mit einem Resolver auflösen
const xml = `<feed xmlns="http://www.w3.org/2005/Atom">
<entry><title>Erster Beitrag</title></entry>
<entry><title>Zweiter Beitrag</title></entry>
</feed>`;
const doc = new DOMParser().parseFromString(xml, 'application/xml');
const resolver = (prefix) => (prefix === 'atom' ? 'http://www.w3.org/2005/Atom' : null);
const iter = new XPathEvaluator().evaluate(
'//atom:entry/atom:title',
doc,
resolver,
XPathResult.ORDERED_NODE_ITERATOR_TYPE,
null
);
let node;
while ((node = iter.iterateNext())) {
console.log(node.textContent);
}
// Wichtig · Fallstricke
- Iterator ungültig nach DOM-Änderung: Bei
*_ITERATOR_TYPEwirftiterateNext()einenInvalidStateError, wenn das Dokument während der Iteration verändert wird. Willst du gefundene Knoten verändern oder entfernen, nimmORDERED_NODE_SNAPSHOT_TYPE. - Falscher Ergebnistyp: Greifst du auf eine Eigenschaft zu, die nicht zum
resultTypepasst (z. B.numberValuebei einer Knotenmenge), wird einTypeErrorgeworfen. BeiANY_TYPEimmerresult.resultTypeprüfen. - Namensräume: In XML-Dokumenten mit Standard-Namensraum (z. B. XHTML, Atom, SVG) findet
//entrynichts. Hier brauchst du ein Präfix und einen Resolver. In HTML-Dokumenten können Elementnamen dagegen ohne Präfix verwendet werden. - Nur XPath 1.0: Browser unterstützen ausschließlich XPath 1.0, also keine Funktionen wie
matches(),lower-case()oder Sequenzen aus XPath 2.0/3.x. - Ungültige Ausdrücke lösen eine
SyntaxError-DOMExceptionaus. Deshalb Ausdrücke aus Benutzereingaben intry…catchauswerten und nie ungeprüft per Zeichenkettenverkettung zusammenbauen (XPath-Injection). - Kompatibilität: Wird von allen modernen Browsern unterstützt. Der Internet Explorer kannte die Methode nicht. Node.js hat kein eingebautes DOM/XPath, dort brauchst du Bibliotheken wie
jsdomoderxpath. - Leistung: Wird derselbe Ausdruck oft ausgewertet, kompiliere ihn einmal mit
createExpression()vor und rufe dannXPathExpression.evaluate()auf.