xpath()
SimpleXMLElement::xpath() esegue query XPath su documenti XML in PHP e restituisce i nodi corrispondenti con SimpleXML.
Introduzione
SimpleXMLElement::xpath() esegue una query XPath su un documento XML caricato con l'estensione SimpleXML di PHP e restituisce i nodi corrispondenti. Senza di essa, puoi solo scorrere un albero XML proprietà per proprietà ($xml->book->title); con essa, puoi raggiungere direttamente qualsiasi nodo — indipendentemente dalla profondità — usando una singola espressione di percorso come //book/title.
Questa pagina spiega cosa restituisce xpath(), la sintassi XPath più utilizzata, come leggere gli attributi e gestire i namespace, e le insidie più comuni.
Sintassi
public SimpleXMLElement::xpath(string $expression): array|false$expression— l'espressione XPath da valutare, relativa al nodo su cui viene chiamata.- Restituisce — un array di oggetti
SimpleXMLElementper ogni nodo corrispondente, un array vuoto quando non ci sono corrispondenze, ofalsein caso di espressione malformata.
Poiché il risultato è sempre un array, di norma lo si itera con foreach anche quando ci si aspetta una singola corrispondenza.
Primo esempio
Gli esempi seguenti usano simplexml_load_string() per essere eseguiti così come sono, senza file esterni:
<?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";
}Output:
The Pragmatic Programmer
PHP Cookbook//title significa "qualsiasi elemento title a qualsiasi profondità." Il ciclo stampa ogni risultato; convertire un SimpleXMLElement in stringa (operazione implicita con echo) restituisce il suo contenuto testuale.
Espressioni XPath comuni
| Espressione | Seleziona |
|---|---|
/library/book | elementi book figli diretti della radice library |
//book | ogni elemento book, a qualsiasi profondità |
//book/title | il figlio title di ogni book |
//book[1] | il primo book (XPath è indicizzato da 1, non da 0) |
//book[@genre='fiction'] | libri il cui attributo genre è uguale a fiction |
//book[author='Sklar'] | libri con un figlio <author> uguale a Sklar |
//@genre | ogni nodo attributo genre |
Filtrare con un predicato
Un predicato tra parentesi quadre mantiene solo i nodi che soddisfano una condizione:
<?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 matchOutput:
Dune
1 matchLeggere un attributo all'interno del predicato usa @, mentre leggerlo da un nodo risultato usa la sintassi array — (string) $book['genre']. Consulta attributes per il quadro completo.
Lavorare con i namespace XML
Se il documento dichiara namespace, un percorso semplice come //book non restituirà nulla — il parser ha bisogno del prefisso del namespace. Registra un prefisso con registerXPathNamespace() prima, poi usalo nell'espressione:
<?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
}Output:
Clean CodeIl prefisso che registri (l) è locale alla tua query — non deve necessariamente corrispondere al prefisso usato nel documento (lib); solo l'URI del namespace deve coincidere.
Insidie
- Controlla sempre il risultato.
xpath()restituiscefalsein caso di espressione non valida e un array vuoto se non ci sono corrispondenze.foreach (($xml->xpath($e) ?: []) as $n)protegge da entrambi i casi. - I risultati sono oggetti, non stringhe. Esegui il cast con
(string)quando hai bisogno del testo:(string) $node. - XPath indicizza da 1.
//book[1]è il primo libro; non esiste[0]. - Il contesto è importante. Chiamare
xpath('title')su un nodobookeffettua la ricerca relativa a quel nodo, mentre un/o//iniziale effettua la ricerca dalla radice del documento indipendentemente da dove lo chiami.
Conclusione
SimpleXMLElement::xpath() trasforma la navigazione profonda e ripetitiva di un albero in una singola query dichiarativa. Combinata con i predicati e la registrazione dei namespace, consente di individuare esattamente i nodi necessari. Abbinala a simplexml_load_string() o all'API SimpleXML più ampia per leggere e trasformare XML in poche righe.