A veces leer, escribir o modificar archivos o cadenas XML no es suficiente, hay que hacer búsquedas dentro de los nodos y atributos. Hace un par de meses me vi en dicha necesidad: tenía un archivo XML con los datos de alumnos que deben mensualidades del colegio. Todos tenían un nombre de usuario asignado y un password. El script consistía en hacer una consulta enviando el nombre y password y después de buscar al alumno en el archivo, había que imprimir los meses o recibos que debía.
Este tipo de problemas se resuelven con XPath. Este lenguaje sirve para navegar por el documento XML como si fuera un árbol tomando en cuenta los elementos y atributos. En w3schools hay un tutorial de XPath en inglés bastante sencillo. Su sintaxis es fácil de entender, mucho más que las expresiones regulares.
Si ya tienen una idea de qué es y cómo funciona XPath, les muestro a continuación cómo se efectúa una búsqueda sencilla para el problema anterior.
Primero, el XML estaba conformado de la siguiente manera (estoy omitiendo algunos atributos para mayor sencillez):
Tengo que aclarar que por motivos muy particulares la contraseña estaba visible y sin encriptación. Esto es porque no se necesitaba de ninguna gestión de seguridad. Cada padre de familia podía acceder para ver los recibos pendientes de pago nada más. En caso de que alguien robara la contraseña de otro alumno, lo peor que podía pasar era que la otra persona pagara por nosotros lo cual sería muy bueno jajaja.
Como en este caso lo que necesito es validar los valores de los atributos «Us» y «Pw», necesito usar la sintaxis:
//elemento[@atributo='valor']
En otras palabras, necesito buscar donde el usuario sea igual a algo y contraseña sea igual a algo. Así que ademas de usar la sintaxis mencionada tengo que usar un operador AND. De modo que el XPath real sería algo asi:
/recibos/r[(@Us='$user') and (@Pw='$psw')]
La expresión /recibos/r
es para hacer referencia a que estoy en el elemento que a su vez está dentro del elemento raíz .
Ahora, ¿cómo usar XPath en PHP? Hace tiempo escribi vagamente sobre el uso básico de la clase SimpleXMLElement de PHP5. Pues esta clase también tiene una implementación de XPath. Tan solo hay que instanciarla con los atributos necesarios y luego llamar a la función SimpleXMLElement::xpath($path) con la sintaxis que necesitemos y nos regresará un objeto SimpleXMLElement para que podamos trabajarlo.
Veamos. Después de hacer un formulario para pedir nombre y contraseña, el script que recibe los datos del POST es algo así:
$user = (!empty($_POST['user']))? $_POST['user'] : null; $psw = (!empty($_POST['psw']))? $_POST['psw'] : null; if(is_null($u) || is_null($p)){ // Error. No puede dejar campos vacios. } // Llamamos a la funcion que buscara los recibos find_receipts($user, $psw); function find_receipts($u, $p){ try { // Se instancia la clase con el archivo XML $xml = new SimpleXMLElement('recibos.xml', null, true); // Se ejecuta la busqueda xpath con la sintaxis apropiada $results = $xml->xpath("/recibos/r[(@Us='$u') and (@Pw='$p')]"); if(empty($results)){ return null; } return $results; } catch(Exception $e) {} }
El objeto regresado contiene todos los elementos que coinciden en la busqueda. En mi caso, los alumnos pueden estar repetidos porque cada elemento es un recibo y cada alumno puede deber uno o más recibos. Así que en ocasiones el script me puede regresar un objeto hasta con 10 elementos o recibos que puedo mostrar con una lista de HTML con los enlaces correspondientes donde puedo mostrar los pormenores del recibo como el monto a pagar, la cuenta bancaria, el numero de recibo, etc.
Aunque mi script no tiene la menor importancia, lo describí para ser más claro al explicar la utilidad de XPath en este problema particular.
Puedes documentarte más sobre la sintaxis y los operadores que puedes usar. Hay mucho de donde leer, lo que casi no hay son ejemplos de cómo implementarlo con PHP. Y aquí les puse una pequeña muestra usando SimpleXMLElement.