xpath()
Aprende a usar SimpleXMLElement::xpath() en PHP para ejecutar consultas XPath sobre documentos XML y obtener nodos coincidentes.
Introducción
SimpleXMLElement::xpath() ejecuta una consulta XPath sobre un documento XML cargado con la extensión SimpleXML de PHP y devuelve los nodos coincidentes. Sin ella, solo puedes recorrer un árbol XML propiedad a propiedad ($xml->book->title); con ella, puedes saltar directamente a cualquier nodo —sin importar su profundidad— usando una única expresión de ruta como //book/title.
Esta página explica qué devuelve xpath(), la sintaxis XPath que más usarás, cómo leer atributos y manejar espacios de nombres, y los errores comunes que suelen confundir a los desarrolladores.
Sintaxis
public SimpleXMLElement::xpath(string $expression): array|false$expression— la expresión XPath a evaluar, relativa al nodo sobre el que se llama.- Devuelve — un array de objetos
SimpleXMLElementpor cada nodo coincidente, un array vacío cuando no hay coincidencias, ofalsesi la expresión es incorrecta.
Dado que el resultado siempre es un array, normalmente se itera con foreach incluso cuando se espera una sola coincidencia.
Un primer ejemplo
Los ejemplos a continuación usan simplexml_load_string() para poder ejecutarse tal cual, sin ningún archivo externo:
<?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";
}Salida:
The Pragmatic Programmer
PHP Cookbook//title significa "cualquier elemento title a cualquier profundidad." El bucle imprime cada resultado; convertir un SimpleXMLElement a string (realizado implícitamente por echo) devuelve su contenido de texto.
Expresiones XPath comunes
| Expresión | Selecciona |
|---|---|
/library/book | elementos book que son hijos directos del elemento raíz library |
//book | todo elemento book, a cualquier profundidad |
//book/title | el hijo title de cada book |
//book[1] | el primer book (XPath indexa desde 1, no desde 0) |
//book[@genre='fiction'] | libros cuyo atributo genre es igual a fiction |
//book[author='Sklar'] | libros con un elemento hijo <author> igual a Sklar |
//@genre | todo nodo de atributo genre |
Filtrado con un predicado
Un predicado entre corchetes conserva solo los nodos que cumplen una condición:
<?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 matchSalida:
Dune
1 matchLeer un atributo dentro del predicado usa @, mientras que leerlo desde un nodo resultado usa sintaxis de array — (string) $book['genre']. Consulta attributes para ver el panorama completo.
Trabajo con espacios de nombres XML
Si el documento declara espacios de nombres, una ruta simple como //book no devolverá nada — el analizador necesita el prefijo del espacio de nombres. Registra un prefijo con registerXPathNamespace() primero y luego úsalo en la expresión:
<?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
}Salida:
Clean CodeEl prefijo que registras (l) es local a tu consulta — no tiene que coincidir con el prefijo usado en el documento (lib); solo debe coincidir el URI del espacio de nombres.
Errores comunes
- Verifica siempre el resultado.
xpath()devuelvefalseante una expresión inválida y un array vacío si no hay coincidencias.foreach (($xml->xpath($e) ?: []) as $n)protege contra ambos casos. - Los resultados son objetos, no strings. Convierte con
(string)cuando necesites el texto:(string) $node. - XPath indexa desde 1.
//book[1]es el primer libro; no existe el[0]. - El contexto importa. Llamar a
xpath('title')en un nodobookbusca relativo a ese nodo, mientras que un/o//inicial busca desde la raíz del documento independientemente de dónde se llame.
Conclusión
SimpleXMLElement::xpath() convierte el recorrido profundo y repetitivo de árboles en una única consulta declarativa. Combinado con predicados y registro de espacios de nombres, permite ubicar exactamente los nodos que necesitas. Úsalo junto con simplexml_load_string() o la API más amplia de SimpleXML para leer y transformar XML en pocas líneas.