Oct 312014
 
Artículo PHP

El formato XML es utilizado frecuentemente para intercambiar datos entre distintas aplicaciones.

La manera más sencilla de procesar estos datos es utilizar algún procedimiento que lee el documento entero y convierte los elementos que contiene a una estructura de datos nativa del lenguaje de programación utilizado. En el caso de PHP, el resultado sería un array asociativo de valores, cada uno de los cuales sería a su vez una array asociativo o bien un valor primitivo, de tipo numérico o de tipo texto.

Pero en ocasiones el volumen de datos a procesar es muy elevado, y puede ser necesario trabajar con documentos XML contenidos en ficheros de varios Gigabytes. En estos casos, los recursos de memoria disponibles pueden no ser suficientes para contener el documento entero en memoria, y es necesario leer el fichero elemento a elemento, y procesar cada uno de los elementos conforme se van leyendo. En este artículo se presenta la forma de realizar este tipo de proceso en lenguaje PHP.

1. Abrir el fichero XML

A partir de PHP 5.1, está disponible la clase XMLReader, que permite procesar documentos XML de gran tamaño.

En primer lugar, abrimos el fichero con una llamada al método “open” de la clase XMLReader:

$fichero = "datos.xml";
$lector = new XMLReader();
$lector->open($fichero);

Pero a menudo, el fichero a leer está comprimido para reducir el espacio en disco que requiere (en XML se consiguen normalmente grandes relaciones de compresión). En este caso, podemos utilizar un filtro de compresión estándar de PHP para realizar la lectura:

$fichero = 'compress.zlib://datos.xml.gz';
$lector = new XMLReader();
$lector->open($fichero);

2. Bucle de lectura de elementos XML

Tras abrir el lector del documento, utilizamos el método “read” para ir leyendo los elementos que contiene:

while ($lector->read()) {
    echo "Nombre del elemento: " . $lector->name . ", tipo: " . $lector->nodeType . "\n";
}

En el ejempo, para cada elemento leido imprimimos el nombre y el tipo del elemento, disponibles en las propiedades “name” y “nodeType” del objeto $lector.

Ademas de “name” y “nodeType”, toda la información referente al elemento está disponible en forma de propiedades del objeto $lector. Entre ellas están:

  • name – nombre del elemento
  • nodeType – número entero que indica el tipo de elemento. Los tipos están definidos también como constantes de la clase XMLReader, como sigue:
  • ( 1: Elemento, 2: Atributo, 3: Texto, etc.) La relación completa se puede consultar en la documentación oficial de XMLReader.
  • isEmptyElement – Booleano. True si el elemento no tiene un valor ni contiene subelementos.
  • hasAttributes – Booleano. True si el elemento tiene atributos asignados
  • attributeCount  – número de atributos del elemento
  • hasValue  – Booleano. True si el elemento tiene un valor asignado. False para elementos de la forma <elemento />
  • value – Valor del elemento ( el contenido entre <elemento> y </elemento>)

Además de los atributos que contienen la información del elemento leído, el objeto $lector implementa una serie de métodos para acceder a la misma:

  • getAttribute($nombre) – Devuelve el valor de un atributo cuyo nombre se le pasa como argumento
  • readInnerXML() – Devuelve el código XML del contenido del nodo en forma de una cadena de texto en formato XML
  • readOuterXML() – Devuelve el código XML de un nodo y su contenido, en forma de una cadena de texto en formato XML
  • etc…

3. Proceso de cada elemento mediante SimpleXML

Los elementos del documento XML se pueden procesar utilizando únicamente las propiedades y métodos de la clase XMLReader. Sin embargo, el código resultante puede llegar a ser difícil de leer.

Por otra parte, en la mayoría de los casos, los documentos XML de gran tamaño a procesar consisten en una colección de un gran número de elementos de un mismo tipo, cada uno de los cuales puede ser convertido a una estructura de datos PHP en memoria sin problemas. En estos casos resulta interesante combinar XMLReader con SimpleXML.

Podemos tomar como ejemplo un documento que contiene una colección de elementos del tipo “direccion”, cada uno de los cuales contiene subelementos “pais”, “ciudad”, “calle”, etc. Además, cada elemento “direccion” tiene un atributo “id”:

<?xml version="1.0" encoding="utf-8"?>
<direcciones>
    <direccion id="1">
        <pais><![CDATA[Mexico]]></pais>
        <ciudad><![CDATA[Monterrey]]></ciudad>
        <calle><![CDATA[Benito Juárez]]></calle>
    </direccion>
    <direccion id="2">
        ...
    </direccion>
</direcciones>

Podemos procesar el fichero en un bucle de la forma:

while ($lector->read()) {
    if($lector->nodeType == XMLReader::ELEMENT && $lector->name == 'direccion' ) {
        // Para cada elemento del tipo "direccion":
        $direccion = new SimpleXMLElement($lector->readOuterXml());
        $atributos = $direccion->attributes();
        echo "ID: " . $atributos->id .
             ", pais: " . $direccion->pais . 
             ", ciudad: " . $direccion->ciudad . 
             ", calle: " . $direccion->calle . "\n";
    }
}

y ejecutando el bucle sobre los datos de ejemplo de arriba, obtenemos el resultado:

ID: 1, pais: Mexico, ciudad; Monterrey, calle: Benito Juárez
ID: 2, ...

Referencias

Indice de artículos sobre programación en PHP

 Publicado por en 5:41 pm

 Deja un comentario

(requerido)

(requerido)