xpath()
SimpleXMLElement::xpath() führt XPath-Abfragen auf XML-Dokumenten in PHP aus und gibt passende Knoten zurück.
Einführung
SimpleXMLElement::xpath() führt eine XPath-Abfrage auf einem XML-Dokument aus, das mit der PHP-Erweiterung SimpleXML geladen wurde, und gibt die übereinstimmenden Knoten zurück. Ohne diese Funktion kann man einen XML-Baum nur Eigenschaft für Eigenschaft durchlaufen ($xml->book->title); mit ihr kann man mit einem einzigen Pfadausdruck wie //book/title direkt zu jedem Knoten springen — egal wie tief er liegt.
Diese Seite erklärt, was xpath() zurückgibt, die am häufigsten verwendete XPath-Syntax, wie man Attribute liest und Namespaces behandelt, sowie typische Fallstricke.
Syntax
public SimpleXMLElement::xpath(string $expression): array|false$expression— der auszuwertende XPath-Ausdruck, relativ zum Knoten, auf dem er aufgerufen wird.- Gibt zurück — ein Array von
SimpleXMLElement-Objekten für jeden übereinstimmenden Knoten, ein leeres Array, wenn nichts übereinstimmt, oderfalsebei einem fehlerhaften Ausdruck.
Da das Ergebnis immer ein Array ist, wird es üblicherweise mit foreach iteriert, auch wenn nur eine Übereinstimmung erwartet wird.
Ein erstes Beispiel
Die folgenden Beispiele verwenden simplexml_load_string(), sodass sie ohne externe Datei direkt ausgeführt werden können:
<?php
$data = <<<XML
<library>
<book genre="fiction">
<title>The Pragmatic Programmer</title>
<author>Hunt</author>
</book>
<book genre="reference">
<title>PHP Cookbook</title>
<author>Sklar</author>
</book>
</library>
XML;
$xml = simplexml_load_string($data);
// Select every <title> anywhere under the root.
foreach ($xml->xpath('//title') as $title) {
echo $title . "\n";
}Ausgabe:
The Pragmatic Programmer
PHP Cookbook//title bedeutet "jedes title-Element auf beliebiger Tiefe." Die Schleife gibt jedes Ergebnis aus; die Umwandlung eines SimpleXMLElement in einen string (durch echo implizit vorgenommen) liefert seinen Textinhalt.
Häufige XPath-Ausdrücke
| Ausdruck | Wählt aus |
|---|---|
/library/book | book-Elemente, die direkte Kinder des Wurzelelements library sind |
//book | jedes book-Element, auf beliebiger Tiefe |
//book/title | das title-Kindelement jedes book |
//book[1] | das erste book (XPath ist 1-indiziert, nicht 0) |
//book[@genre='fiction'] | Bücher, deren genre-Attribut gleich fiction ist |
//book[author='Sklar'] | Bücher mit einem <author>-Kindelement mit dem Wert Sklar |
//@genre | jeder genre-Attributknoten |
Filtern mit einem Prädikat
Ein Prädikat in eckigen Klammern behält nur die Knoten, die einer Bedingung entsprechen:
<?php
$data = <<<XML
<library>
<book genre="fiction"><title>Dune</title></book>
<book genre="reference"><title>PHP Cookbook</title></book>
</library>
XML;
$xml = simplexml_load_string($data);
$fiction = $xml->xpath("//book[@genre='fiction']");
echo $fiction[0]->title . "\n"; // Dune
echo count($fiction) . " match\n"; // 1 matchAusgabe:
Dune
1 matchDas Lesen eines Attributs innerhalb des Prädikats verwendet @, während das Lesen aus einem Ergebnisknoten die Array-Syntax verwendet — (string) $book['genre']. Weitere Einzelheiten finden Sie unter attributes.
Arbeiten mit XML-Namespaces
Wenn das Dokument Namespaces deklariert, gibt ein einfacher Pfad wie //book nichts zurück — der Parser benötigt das Namespace-Präfix. Registrieren Sie zuerst ein Präfix mit registerXPathNamespace() und verwenden Sie es dann im Ausdruck:
<?php
$data = <<<XML
<lib:library xmlns:lib="http://example.com/lib">
<lib:book><lib:title>Clean Code</lib:title></lib:book>
</lib:library>
XML;
$xml = simplexml_load_string($data);
$xml->registerXPathNamespace('l', 'http://example.com/lib');
foreach ($xml->xpath('//l:book/l:title') as $title) {
echo $title . "\n"; // Clean Code
}Ausgabe:
Clean CodeDas von Ihnen registrierte Präfix (l) ist lokal für Ihre Abfrage — es muss nicht mit dem im Dokument verwendeten Präfix (lib) übereinstimmen; nur der Namespace-URI muss übereinstimmen.
Fallstricke
- Ergebnis immer prüfen.
xpath()gibt bei einem ungültigen Ausdruckfalsezurück und bei keiner Übereinstimmung ein leeres Array.foreach (($xml->xpath($e) ?: []) as $n)schützt vor beidem. - Ergebnisse sind Objekte, keine Strings. Mit
(string)umwandeln, wenn der Text benötigt wird:(string) $node. - XPath indiziert ab 1.
//book[1]ist das erste Buch; es gibt kein[0]. - Kontext ist wichtig. Das Aufrufen von
xpath('title')auf einembook-Knoten sucht relativ zu diesem Knoten, während ein führendes/oder//unabhängig vom Aufrufkontext immer vom Dokumentwurzel aus sucht.
Fazit
SimpleXMLElement::xpath() verwandelt tiefes, wiederholendes Baumdurchlaufen in eine einzige deklarative Abfrage. In Kombination mit Prädikaten und Namespace-Registrierung ermöglicht es, genau die benötigten Knoten zu finden. Kombinieren Sie es mit simplexml_load_string() oder der umfassenderen SimpleXML-API, um XML in nur wenigen Zeilen zu lesen und zu transformieren.