Signatur
Beschreibung
document.evaluate() führt einen XPath-1.0-Ausdruck gegen ein HTML- oder XML-Dokument aus. Im Gegensatz zu querySelectorAll() kann XPath Knoten auch anhand ihres Textinhalts auswählen, in der Baumstruktur nach oben navigieren (ancestor::, parent::), Geschwister gezielt ansprechen und direkt Werte wie Zahlen oder Strings berechnen (count(), string(), sum()).
Das Ergebnis ist immer ein XPathResult-Objekt. Welche Eigenschaften oder Methoden darauf sinnvoll sind, hängt vom gewählten resultType ab: singleNodeValue für Einzelknoten, snapshotItem(i)/snapshotLength für Snapshots, iterateNext() für Iteratoren sowie numberValue, stringValue und booleanValue für primitive Ergebnisse.
Typische Einsatzgebiete sind Web-Scraping, Browser-Erweiterungen, End-to-End-Tests, das Auswerten von per DOMParser geladenen XML-Dokumenten (RSS, SVG, XHTML) sowie Fälle, in denen CSS-Selektoren nicht ausdrucksstark genug sind.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $xpathExpression Pflicht | string | Der auszuwertende XPath-1.0-Ausdruck, z. B. //a[@href] oder count(//li). |
|
| $contextNode Pflicht | Node | Knoten, relativ zu dem der Ausdruck ausgewertet wird. Relevant für relative Pfade wie ./td; meist document. |
|
| $namespaceResolver | XPathNSResolver|Function|null | null | Funktion, die Namensraum-Präfixe (z. B. svg) auf Namensraum-URIs abbildet. Für normales HTML null. |
| $resultType | number | XPathResult.ANY_TYPE (0) | Konstante aus XPathResult, z. B. ORDERED_NODE_SNAPSHOT_TYPE, FIRST_ORDERED_NODE_TYPE, ORDERED_NODE_ITERATOR_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE. |
| $result | XPathResult|null | null | Vorhandenes XPathResult zur Wiederverwendung. In der Praxis fast immer null. |
Rückgabewert
XPathResult, dessen Inhalt vom resultType abhängt. Bei ANY_TYPE wählt der Browser den natürlichen Typ (Knotenmengen werden zu UNORDERED_NODE_ITERATOR_TYPE).Beispiele
Button anhand seines Textes finden
// HTML: <button>Abbrechen</button><button>Speichern</button>
const result = document.evaluate(
"//button[normalize-space(text())='Speichern']",
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
const saveButton = result.singleNodeValue;
console.log(saveButton?.textContent);
Alle externen Links als Snapshot sammeln
const $x = (xpath, context = document) => {
const snap = document.evaluate(
xpath, context, null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
);
return Array.from({ length: snap.snapshotLength }, (_, i) => snap.snapshotItem(i));
};
const externalLinks = $x("//a[starts-with(@href, 'http') and not(contains(@href, location.host))]");
// Snapshot bleibt stabil, auch wenn wir das DOM verändern
externalLinks.forEach((a) => a.setAttribute('rel', 'noopener noreferrer'));
console.log(`${externalLinks.length} externe Links markiert`);
Zahlen und Strings direkt berechnen
const count = document.evaluate(
'count(//table[@id="orders"]/tbody/tr)',
document, null, XPathResult.NUMBER_TYPE, null
).numberValue;
const title = document.evaluate(
'string(//h1)', document, null, XPathResult.STRING_TYPE, null
).stringValue;
console.log(count, title);
XML mit Namensraum auswerten (DOMParser)
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 === 'a' ? 'http://www.w3.org/2005/Atom' : null);
const iter = doc.evaluate('//a:entry/a:title', doc, resolver,
XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
let node;
while ((node = iter.iterateNext())) {
console.log(node.textContent);
}
// Wichtig · Fallstricke
- Nur XPath 1.0: Funktionen aus XPath 2.0/3.x wie
matches(),lower-case()oderends-with()gibt es nicht; Groß-/Kleinschreibung lässt sich nur mittranslate()umgehen. - Iteratoren sind fragil: Wird das DOM verändert, während ein
*_ITERATOR_TYPE-Ergebnis durchlaufen wird, wirftiterateNext()eineInvalidStateError-Ausnahme. Zum Verändern von Knoten besserORDERED_NODE_SNAPSHOT_TYPEverwenden. - Falscher Zugriff je nach Typ: Wer z. B.
singleNodeValueauf einem Snapshot-Ergebnis liest, bekommt einenTypeError. DenresultTypealso immer ausdrücklich angeben, statt sich aufANY_TYPEzu verlassen. - Namensräume: In XML-Dokumenten mit Standard-Namensraum (Atom, SVG, XHTML) findet
//entrynichts. Nötig sind ein Präfix und einnamespaceResolver. In HTML-Dokumenten werden HTML-Elemente dagegen ohne Präfix gefunden. - Sicherheit: Nutzereingaben nie ungeprüft in XPath-Ausdrücke einsetzen (XPath-Injection). Anführungszeichen maskieren oder das Ergebnis erst nachträglich in JavaScript filtern.
- Leistung: Für einfache Abfragen ist
querySelector()meist schneller und besser lesbar.//am Anfang durchsucht das ganze Dokument, deshalb besser einen engencontextNodemit relativem Pfad (.//) nutzen. - Kompatibilität: Wird von allen modernen Browsern unterstützt, im Internet Explorer gab es das nicht. In Node.js fehlt es ohne DOM-Bibliothek;
jsdombringt es mit.