Cómo recorrer un archivo XML usando PHP

Como de costumbre, comencemos por ponernos de acuerdo en las definiciones.

Qué es XML

Las siglas XML remiten a eXtensible Markup Language (Lenguaje de etiquetas extendible).

Se trata de texto estructurado mediante etiquetas (Palabras encerradas entre < y >):

<utensilios>
  <tenedor/>
  <cuchillo/>
</utensilios>

Para qué sirve XML

XML se inventó como un medio de intercambio de información entre sistemas a través de Internet. Al ser un formato basado en texto, era fácil aprovechar la infraestructura existente para comunicarse a través de HTTP.

Hoy en día, XML es utilizado en muchas implementaciones de WebServices (Por ejemplo, las facturas electrónicas) y también para almacenar configuraciones (En el caso del lenguaje Java es muy común encontrar este tipo de archivos, en PHP no tanto).

Cómo se procesa XML usando PHP

Al tratarse de texto, un modo de procesar XML es, como cualquier otro texto… pueden usarse expresiones regulares u otro medio de análisis de texto para interpretar y/o generar las etiquetas.

Claro que no es muy divertido que digamos…


Para comprender completamente lo que viene a continuación se requieren conocimientos de Programación Orientada a Objetos con PHP. Si aún no lo tenés muy claro este curso te puede ayudar.


Otro modo bastante más práctico es usar la biblioteca SimpleXML que viene con PHP.

La clase principal de la biblioteca es SimpleXMLElement. Con esta clase se puede crear una estructura en memoria a partir de un texto XML y luego recorrerlo en forma sencilla.

Ejemplo de lectura de XML con SimpleXMLElement

El constructor de SimpleXMLElement recibe un texto XML:

<?php
$xml = new SimpleXMLElement( '<utensilios><tenedor/><cuchillo/></utensilios>' );

Y a partir de ahí pueden realizarse diversas operaciones para recorrer los elementos.

Una de ellas es buscar elementos explícitamente a través de su XPATH:

$elementos = $xml->xpath('/utensilios/tenedor');

Esta llamada dejará en el array $elementos todos los nodos tenedor que se encuentren bajo la clave utensilios (En este caso es sólo uno, pero eso SimpleXMLElement no lo sabe a priori).

Si agregamos un print_r( $elementos ) veremos :

Array
(
    [0] => SimpleXMLElement Object
        (
        )

)

Es decir, un array con un único elemento… de tipo SimpleXMLElement, al que podemos nuevamente aplicarle todas las funciones que provee la clase.

Ejemplo de recorrida de XML con SimpleXML

Otra forma de recorrer el texto XML es a través del método children:

<?php
$xml = new SimpleXMLElement( '<utensilios><tenedor/><cuchillo/></utensilios>' );
foreach ( $xml->children() as $child ) {
        print_r( $child );
}

Esta es la que deberías usar si no conoces exactamente la estructura del XML o si efectivamente tenés que recorrer el archivo completo.

Cómo leer un archivo XML usando PHP

Bueno, con lo que viste hasta ahora el paso que queda es realmente corto… se podría leer el contenido del archivo a una variable y pasarla al constructor de SimpleXMLElement:

<?php
$texto = file( 'archivo.xml' );
$xml = new SimpleXMLElement( $texto );
$elementos = $xml->xpath('/utensilios/tenedor');
print_r( $elementos );

O bien pasar directamente la ruta al archivo al constructor:

<?php
$xml = new SimpleXMLElement( 'archivo.xml' );
$elementos = $xml->xpath('/utensilios/tenedor');
print_r( $elementos );

Y dejar que SimpleXML se encargue de interpretar si se trata de uno u otro.

Conclusión

Si todavía no te convencí de usar SimpleXML en lugar de hacer las cosas a mano, te invito a leer un poco más sobre el formato XML (Especialmente el manejo de namespaces).

Ahora, si tenés que interactuar con un sistema que está implementado usando XML, bueno… no hay muchas opciones.

Si, por el contrario, estás pensando en usar algún formato de texto para guardar configuración o incluso para intercambiar con otros sistemas, te sugiero darle una mirada a JSON o a YAML

mchojrin

Por mchojrin

Ayudo a desarrolladores PHP a acceder mercados y clientes más sofisticados y exigentes

11 comentarios

  1. Estimado don Mauro: Le comento que tengo unos xml de respuesta que vienen de un Soap, pero a mi criterio son muy complejos para leerlos y me gustaria que me diera un consejo de como extraer algunos campos de estos xml.

    Le detallo una de las respuestas

    de este xml debo extraer
    Job JobName y
    ContextId

    Agradezco su ayuda

  2. muchas gracias, me sirvio de mucho, un cliente nos envia la informacion usando soap y a cada rato me quedaba sin memoria. aun asi me gusta mas json

    1. Y sí… la verdad es que SOAP no es precisamente la imagen de la eficiencia, ja.

      Es sólo que en ocasiones json (O RESTful en realidad) se queda algo corto por la complejidad de la información a intercambiar.

      ¿Cómo resolviste el problema de la falta de memoria?

  3. creo un array multidimencional asociativo a partir de un xml
    cuando llega a una linea de detalle me crea indices repetidos y me da el siguiente error
    Notice: Undefined index: NumeroLinea

  4. Hola Mauro !

    Primero felicitarte por el aporte que realizas a través de tu sitio y canales, el cual sigo desde hace ya un tiempo.

    Acudo a tu persona, y apelando a tu experiencia y basto conocimiento de PHP :), luego de que llevo unos días intentando «leer» la respuesta de un WS SOAP, específicamente la respuesta del método «Login». Al principio tuve problemas para «conectar», me fue imposible realizarlo con la clase SoapClient, por lo lo tuve que hacer con cURL.

    Ahora que ya obtengo la respuesta, recibo los datos en un XML con la siguiente estructura:



    VentaServicio/VentaServicio/LoginResponse

    cliente
    empresa
    id_sesion
    id_usuario
    token_encriptado

    La verdad, e probado de todas las maneras y formas posible de acceder y obtener el VALOR del «Token» para luego utilizarlo en el resto de los métodos, pero ninguna me a sido posible. Lo más extraño, es que aplicando las mismas técnicas a otras «respuestas» SOAP de ejemplo encontradas, y de mayor complejidad, sí puedo leer sus valores sin problemas. Lamentablemente, no he encontrado ninguna «respuesta» con similar estructura que muestre su correcta manera de recorrerla o de lectura. Sumado a que el «namespace» de LoginResponse me reclama que no tiene una ruta «absoluta» (cosa que solucioné, temporalmente, añadiendo el http://).

    $oXML = simplexml_load_string($sXML);

    // Now we will register namespace.
    $oXML->registerXPathNamespace(‘res’, ‘http://www.w3.org/2003/05/soap-envelope’);
    print_r($oXML->registerXPathNamespace(‘res’, ‘http://www.w3.org/2003/05/soap-envelope’));
    echo «\n\n»;
    // Now you can use XPATH to go to specific nodes
    $result = $oXML->xpath(‘//res:Body/LoginResponse/LoginResult’);

    foreach ($result as $node){
    print_r($node);
    }

    // convierte xml a json
    $json = json_encode($result);
    print_r($json);
    echo «\n\n»;
    // convierte json a array assoc
    $vars = json_decode($json, true);
    foreach($vars as $valor){
    print_r($valor);
    }

    Que cosas crees que pueda estar pasando por alto o haciendo mal, de manera que me esté costando tanto lograr mi objetivo.

    Desde ya, te agradezco cualquier comentario o ayuda.

    Saludos !

    1. Hola Jonathan!

      Gracias por tus palabras, me alegra que te agraden mis contenidos 🙂

      Empezaría por preguntarte qué es lo que no te ha funcionado al usar la clase SoapClient. Ciertamente, para comunicarse con WebServices de tipo SOAP es de lo mejorcito.

      Puedes leer algo más en este post.

      A simple vista no veo nada extraño, aunque es difícil leer el código así (sin formato).

      Mi sugerencia es que intentes nuevamente con SoapClient y, de ser imposible, que intentes con algún debugger, seguro que así podrás encontrar tu problema.

      Exitos!

  5. el xml me regresa otro xml ¿como puedo leer ese xml si no conozco su contenido? ya intente guardarlo pero me marca un error

    1. Hola Raúl!

      No sé si entiendo bien tu problema… ¿qué significa «el xml me regresa otro xml»? ¿De dónde te lo regresa? ¿Podrías contar un poco más de detalle sobre lo que estás haciendo y lo que intentas lograr?

      Si no conoces la estructura del xml que estás tratando de leer se hará algo complicado recorrerlo… podrías intentar algo como una lectura recursiva, arrancando por el elemento raíz e iterar por sus children…

      Por último, ¿puedes comentar qué error estás viendo?

      Exitos!

¿Te quedó alguna duda? Publica aca tu pregunta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.