DomDocument en PHP

12 Jul

Los archivos de tipo XML son muy útiles y suelen ser utilizados por la mayoría de los lenguajes de programación, en PHP no es la excepción. Si bien las aplicaciones web suelen trabajar con bases de datos como MySQL, para, valga la redundancia guardar datos, trabajar con XML también nos da la posibilidad de guardar información.

Generar un archivo XML con PHP es muy sencillo, simplemente podríamos generar un texto con formato XML como esto:

<?php
$contenido = '<?xml version="1.0"?>
<alumnos><alumno><nombre>Conelio</nombre><apellido>Del Rancho</apellido><nivel>Principiante</nivel></alumno></alumnos>
';
$archivo = fopen('alumnos.xml', 'w');
fwrite($archivo, $contenido);
fclose($archivo); 
?>

Gracias a la función fopen() de PHP podemos crear o modificar archivos, luego con fwrite() escribimos dentro del mismo su contenido y finalmente con fclose() cerramos el archivo.

Sin embargo esto nos permite solamente crear archivos, independientemente de si son .xml, .txt. .yml; etc. Nosotros necesitamos algo que nos permita trabajar con los nodos de un XML. Para ello usaremos la clase de PHP DomDocument.

 

Crear un XML

DomDocument permite manipular un XML así como Javascript lo hace con HTML. DomDocument nos da la posibilidad de crear un XML y guardarlo, modificarlo, eliminar nodos y mostrar su contenido. Para ello vamos a comenzar un pequeño proyecto.

Un profesor de guitarra necesita guardar el nombre, apellido y nivel de todos sus alumnos. Entonces suponiendo que nosotros tenemos un array asociativo con este aspecto:

$alumnos_array = array(
   array(
      'nombre' => 'Cosme',
      'apellido' => 'Fulanito',
      'nivel' => 'Principiante'
   ),
   array(
      'nombre' => 'Cornelio',
      'apellido' => 'Del Rancho',
      'nivel' => 'Intermedio'
   ),
   array(
      'nombre' => 'Lalo',
      'apellido' => 'Landa',
      'nivel' => 'Avanzado'
   )
);

Ahora deberíamos crear un XML con los datos del array.

En primer lugar vamos instanciar un objeto de la clase DomDocument de la siguiente manera:

$documento = new DOMDocument("1.0");

Este objeto al ser creado recibirá como parámetro la versión, en nuestro caso 1.0. Y además contará con ciertos método, uno de ellos es createElement() que nos permitirá crear nodos con su respectivo nombre. Por tanto crearemos un nodo principal llamado alumnos:

$alumnos = $documento->createElement('alumnos');

A su vez el nodo alumnos tendrá varios nodos de nombre alumno y estos tres más llamados: nombre, apellido y nivel.

Así que crearemos los nodos:

$alumno = $documento->createElement('alumno');
$nombre = $documento->createElement('nombre', 'El nombre');
$apellido = $documento->createElement('apellido', 'El apellido');
$nivel = $documento->createElement('nivel', 'El nivel');

createElement() recibirá como primer parámetro y obligatorio el nombre del nodo y como segundo parámetro y opcional el valor.

Ahora sólo nos queda agregar los nodos hijos en los nodos padres: nombre, apellido y nivel dentro de alumno mediante el método appendChild():

$alumno->appendChild($nombre);
$alumno->appendChild($apellido);
$alumno->appendChild($nivel);

El nodo alumno al nodos alumnos:

$alumnos->appendChild($alumno);

Y finalmente vamos a agregar alumnos al objeto instanciado para que tenga efecto al guardarlo:

$documento->appendChild($alumnos);

Para guardar el XML debemos usar el método save():

$documento->save('alumnos.xml');

También podemos agregar atributos a los nodos, por ejemplo:

$alumno->setAttribute('atributo', 'valor');

De esta manera entonces nosotros podemos recorrer el array con un foreach para crear un árbol completo:

<?php
   $alumnos_array = array(
   array(
      'nombre' => 'Cosme',
      'apellido' => 'Fulanito',
      'nivel' => 'Principiante'
   ),
   array(
      'nombre' => 'Cornelio',
      'apellido' => 'Del Rancho',
      'nivel' => 'Intermedio'
   ),
   array(
      'nombre' => 'Lalo',
      'apellido' => 'Landa',
      'nivel' => 'Avanzado'
   )
);
$documento = new DOMDocument("1.0");
//Nodo alumnos.
$alumnos = $documento->createElement('alumnos');
//Contador autoincrementable en cada vuelta de alumno.
$nodo_contador = 1;
foreach ($alumnos_array as $vuelta) {
   //Nodo alumno.
   $alumno = $documento->createElement('alumno');
   //Número del nodo
   $alumno->setAttribute('nodo', $nodo_contador); 
   $nodo_contador++;
   //Nombre nombre
   $nombre = $documento->createElement('nombre', $vuelta['nombre']);
   //Nombre apellido
   $apellido = $documento->createElement('apellido', $vuelta['apellido']);
   //Nombre nivel
   $nivel = $documento->createElement('nivel', $vuelta['nivel']);
   //Agregamos los nodos hijos.
   $alumno->appendChild($nombre);
   $alumno->appendChild($apellido);
   $alumno->appendChild($nivel);
   $alumnos->appendChild($alumno);
}
//Agregamos todo el árbol al objeto.
$documento->appendChild($alumnos);
//Guardamos el XML.
$documento->save('alumnos.xml'); 
?>

Esto nos creará el siguiente árbol:

<?xml version="1.0"?>
<alumnos>
   <alumno nodo="1">
      <nombre>Cosme</nombre>
      <apellido>Fulanito</apellido>
      <nivel>Principiante</nivel>
   </alumno>
   <alumno nodo="2">
      <nombre>Cornelio</nombre>
      <apellido>Del Rancho</apellido>
      <nivel>Intermedio</nivel>
   </alumno>
   <alumno nodo="3">
      <nombre>Lalo</nombre>
      <apellido>Landa</apellido>
      <nivel>Avanzado</nivel>
   </alumno>
</alumnos>

 

Mostrar nodos

Bien, ahora que creamos nuestro XML también podemos recuperar los datos que hemos guardado. Primero debemos cargar nuestro XML de la siguiente forma:

$documento = new DOMDocument();
$documento->load('alumnos.xml');

El método load será el encargado de completar el objeto con los datos del XML.

Ahora, para recuperar los distintos nodos debemos usar el método getElementsByTagName(), que recibirá como parámetro el nombre del nodo y el método item() que recibirá como parámetro el número del nodo empezando desde cero. Por ejemplo si quisiéramos recuperar el nombre del segundo nodo (Cornelio) entonces deberíamos hacer lo siguiente:

$nombre = $documento->getElementsByTagName('nombre')->item(1);

Y para recuperar su valor:

echo $nombre->nodeValue;

Con saber esto entonces ya podemos recuperar todos los nodos de la siguiente forma:

<?php
   $documento = new DOMDocument();
   //Cargamos el XML que queremos tratar.
   $documento->load('alumnos.xml');
   //Guardamos la cantidad de alumnos que hay.
   $cantidad_de_alumnos = $documento->getElementsByTagName('alumno')->length;
   //Recorremos los alumnos con un for.
   for($i = 0; $i < $cantidad_de_alumnos; $i++){
      $nombre = $documento->getElementsByTagName('nombre')->item($i)->nodeValue;
      $apellido = $documento->getElementsByTagName('apellido')->item($i)->nodeValue;
      $nivel = $documento->getElementsByTagName('nivel')->item($i)->nodeValue;
      echo "{$nombre} {$apellido} (Nivel: {$nivel})";
      echo '<br />';
   }
?>

Otra alternativa también podría ser recuperar el nombre, apellido y nivel pero no desde el nombre de sus respectivos nodos, sino desde el nodo padre que es alumno. En este caso deberíamos usar la propiedad childNodes que con le método item() nos dará la posición del hijo que necesitamos. El nodo nombre sería la posición 0, apellido la posición 1 y nivel la 2. Así que podríamos cambiar el for:

for($i = 0; $i < $cantidad_de_alumnos; $i++){
   $nombre = $documento->getElementsByTagName('nombre')->item($i)->nodeValue;
   $apellido = $documento->getElementsByTagName('apellido')->item($i)->nodeValue;
   $nivel = $documento->getElementsByTagName('nivel')->item($i)->nodeValue;
   echo "{$nombre} {$apellido} (Nivel: {$nivel})";
   echo '<br />';
}

Por esto:

for ($i = 0; $i < $cantidad_de_alumnos; $i++) {
   $alumno = $documento->getElementsByTagName('alumno')->item($i);
   $nombre = $alumno->childNodes->item(0)->nodeValue;
   $apellido = $alumno->childNodes->item(1)->nodeValue;
   $nivel = $alumno->childNodes->item(2)->nodeValue;
   echo "{$nombre} {$apellido} (Nivel: {$nivel})";
   echo '<br />';
}

 

Modificar nodos

Así como podemos recuperar nodos, también podemos cambiarle su valor y de luego guardar el archivo. Por ejemplo si quisiéramos modificar el nombre y apellido del tercer nodo alumno (índice 2) podríamos hacerlo de la siguiente forma:

<?php
   $documento = new DOMDocument();
   //Cargamos el XML que queremos tratar.
   $documento->load('alumnos.xml');
   //Recuperamos el nodo alumno con la posición 2.
   $alumno = $documento->getElementsByTagName('alumno')->item(2);
   //Recuperamos el nombre y el apellido.
   $nombre = $alumno->childNodes->item(0);
   $apellido = $alumno->childNodes->item(1);
   //Le seteamos los nuevos valores.
   $nombre->nodeValue = 'Beto';
   $apellido->nodeValue = 'Velez';
   //Guardamos el archivo.
   $documento->save('alumnos.xml');
?>

 

Eliminar nodos

Para eliminar un nodo completo debemos recuperar el padre del nodo y luego con el método removeChild() llamar al nodo a eliminar. Por ejemplo alumnos tiene tres nodos alumno, así que vamos a eliminar el tercero (posición 2) de la siguiente forma:

<?php
   $documento = new DOMDocument();
   //Cargamos el XML que queremos tratar.
   $documento->load('alumnos.xml');
   //Recuperamos el nodo padre y el nodo hijo.
   $padre = $documento->getElementsByTagName('alumnos')->item(0);
   $hijo = $padre->childNodes->item(2);
   //Eliminamos desde el padre al hijo.
   $padre->removeChild($hijo);
   //Guardamos el archivo.
   $documento->save('alumnos.xml');
?>

 

Redes sociables

    2 thoughts on “DomDocument en PHP

    Deja un comentario

    Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *


    *