Como ver, crear y editar XML y HTML en PHP con DomDocument

Primero que nada deberíamos saber que es un documento DOM.
DOM son las siglas de Document Object Model o Modelo de objetos del documento en español.

Cuando nació HTML era muchísimo más primitivo y no incorporaba el modelo DOM así que si en algún momento queríamos editar una tabla ‘on-the-fly’ con Javascript nos era imposible… no podíamos «capturar» la tabla y, por ejemplo, agregarle un td como hacemos ahora con Javascript.

Por eso a algún genio se le ocurrió el concepto de DOM y ahora podemos tratar un documento HTML (o XML) y dividirlo por partes (u objetos).

Bueno hasta aquí a modo de cultura general… vamos a suponer que tenemos conocimientos de DOM ya sea porque usamos JavaScript o por algún otro motivo….

Si no es así voy a hacer una rápida aproximación al modelo DOM para que se entienda lo que vamos a hacer.

Ejemplo de un documento dom en html

En esta imagen podemos apreciar un documento HTML bastante simple:

<html>

<body>

<table>
<tbody>
<tr>
<td>Shady Grove</td>
<td>Aeolian</td>
</tr>
<tr>
<td>Over the river, charlie</td>
<td>Dorian</td>
</tr>
</tbody>
</table>

</body>
</html>

Entonces a cada entidad (recuadro) se le llama elemento y cada elemento contiene los elementos inferiores (childs).
En este caso Document es el elemento principal y contiene todos los Elementos inferiores.

El primer tr contiene los dos td inferiores pero no los otros dos.

Entonces si quisiésemos tener todos los tr podemos hacer 2 cosas:

  • Capturar el tbody y sacar sus child’s (hijos)
  • o directamente capturar todos los tr

Para ello usaremos ciertas funciones que vienen en la librería DomDocument.
DomDocument es una librería de PHP creada especialmente para trabajar con documentos DOM, sean XML, HTML, XHTML o cualquier tipo de documento DOM.

Nos será de gran ayuda cuando trabajemos con XML, leyendo feeds o pasando datos de un programa a nuestra web…
En HTML nos será factible a la hora de recuperar datos de una web.

  • getElementById: la más conocida en Javascript, nos proporciona un elemento según su id
  • Ejemplo: <div id=»estaid»> algo </div>
    Nota: nos da todo lo que hay dentro del div, tanto el «algo» como sus parámetros.

  • getElementsByTagName: Nos devuelve un array con todas las entidades con dicho tag name
  • Ejemplo: <div> algo </div>
    Nota: Nos da un array completo lleno de elementos interiores, valores y etiquetas.

    Otras funciones de la clase que eventualmente usaremos:

  • NodeValue: Nos da el valor del Nodo (elemento)
  • Ejemplo: <a href=»http://www.skamasle.com»> Skamaslealo! </a> (Nos da como resultado: Skamaslealo!)

  • Item: Cuando usamos funciones como getElementsByTagName podemos elegir cual de todos los elementos queremos con esta función
  • Nota: item(0) es el primer elemento y no item(1)…

  • CreateElement: cuando queremos crear un elemento, esta será nuestra función
  • AppendChild: (Anexar Hijo) cuando creamos un elemento y queremos hacerlo hijo de otro elemento tenemos que usar esta función
  • CreateTextNode: así como usamos NodeValue para sacar el valor de un nodo, usamos esta función para darle un valor a dicho nodo.

Y diría que con estas funciones podemos seguir adelante.

Leer un documento XML con DomDocument

El primer ejemplo, y el más simple de todos es como leer un documento XML.

El primer paso es crear el objeto y cargar el xml:

$dom = new DOMDocument();
$dom->load('http://www.w3schools.com/XML/cd_catalog.xml');

Usaremos un XML de w3schools.com por comodidad, podéis ver la estructura visitando la URL.

Ahora tomamos los elementos CD y con un bucle recorremos cada elemento mostrando los valores de sus childs.

$cd = $dom->getElementsByTagName('CD');

foreach($cd as $element) {
    
    echo 'Album: '. $element->getElementsByTagName('TITLE')
                           ->item(0)
                           ->nodeValue . '
'; //Los TagName diferencian M de m.. echo 'Artista: '. $element->getElementsByTagName('ARTIST') ->item(0) ->nodeValue . '
'; echo 'Año: ' . $element->getElementsByTagName('YEAR') ->item(0) ->nodeValue . '
'; echo 'Precio: ' . $element->getElementsByTagName('PRICE') ->item(0) ->nodeValue . '

'; }

No creo que haya mucho a comentar, simplemente tomamos de la variable $element cada tagname que nos interese y mostramos el valor del nodo del primer elemento.

Otro ejemplo podría ser que nos interese un elemento en particular, por ejemplo el segundo elemento.

echo 'Album del elemento 2: '. $dom->getElementsByTagName('TITLE')
                                            ->item(1)
                                            ->nodeValue .'';
//recordemos que el 0 es el 1er elemento...

Crear un XML con DomDocument

Otra cosa que nos puede interesar es saber crear un XML.
Este ejercicio puede ser el más difícil de los 3 que vamos a realizar, aún así no es demasiado complicado.

Primero creamos un array:

$books = array();
//suponiendo que estas arrays saldrán de una consulta...
$books[] = array('title' => 'Introducción a PHP5',
                 'autor' => 'David Sklar',
                 'publicacion' => "O'Reilly"
                );
$books[] = array('title' => 'PHP Hacks',
                 'autor' => 'Jack Herrington',
                 'publicacion' => "O'Reilly"
                );

Esta información podría sacarse de una Query a una DataBase, pero así se ve más claro…

Creamos nuestro documento y creamos un elemento que apegaremos al documento

$doc = new DOMDocument();
$doc->formatOutput = true;

$r = $doc->createElement('books'); //Creamos un elemento 
$doc->appendChild($r); //lo pegamos al documento

Es importante recordar que siempre hay que pegar los nuevos elementos a algo… en caso de que queramos que estén en el root por decirlo así hay que pegarlos al documento original.

Esta parte se puede complicar de entender, lo que hacemos es crear un elemento book que irá dentro del elemento books (y habrá tantos book como elementos del array tengamos).

Luego crearemos los elementos autor, titulo y publicación y los pegaremos a cada elemento book.

foreach($books as $book) {
    $b = $doc->createElement("book"); //creamos un elemento 
    
    $autor = $doc->createElement("author"); //cremos elemento 
    $autor->appendChild (  //a  le pegamos el string
     $doc->createTextNode( $book['autor'])
    );
    $b->appendChild($autor); //pegamos  a 
    
    $title = $doc->createElement("title");
    $title->appendChild(
     $doc->createTextNode( $book['title'])
    );
    $b->appendChild($title);
    
    $publisher = $doc->createElement("publisher");
    $publisher->appendChild(
     $doc->createTextNode($book['publicacion'])
    );
    $b->appendChild($publisher);
    
    $r->appendChild($b);   //pegamos  a 
}

Finalmente guardaremos el XML y lo mostraremos:

echo $doc->saveXML();

Y la salida que dará el XML es:

<?xml version="1.0"?>
<books>
<book>
<author>David Sklar</author>
<title>Introducci&#xEE821; PHP5</title>
<publisher>O'Reilly</publisher>
</book>
<book>

<author>Jack Herrington</author>
<title>PHP Hacks</title>
<publisher>O'Reilly</publisher>
</book>
</books>

Leer un HTML con DomDocument

El último ejemplo trata de leer un HTML. En este caso nos interesa conseguir los títulos de los posts publicados en Skamasle.

Como estamos trabajando con una página web dinámica los resultados variarán según el tiempo en el que se ejecute el script.

Antes que nada, ocultamos el reporte de errores.
Lo hacemos porque salen algunos errores de sintaxis en el parser de DOMDocument con el blog de Skamasle.

Luego usamos una función que hice hace mucho para sacar datos con Curl y en caso de no tener Curl usar file_get_contents().

Para finalizar esta parte simplemente creamos el objeto y cargamos el HTML.

error_reporting(0);
$curl= curl("http://www.skamasle.com"); //Bajamos el HTML

$doc = new DOMDocument;
$doc->loadHTML($curl); //cargamos el HTML

Como segundo paso vamos a tomar el elemento que más se ajuste a lo que necesitamos, en la estructura actual del blog es el elemento con el Id: primary-content, que si no recuerdo mal es un div.

$primary = $doc->getElementById('primary-content');

Luego tomamos todos los elementos h2 dentro del div que son los títulos de cada post.

Y finalmente recorremos con un bucle cada artículo para sacar el valor del nodo y mostrarlo.

$articles = $primary->getElementsByTagName('h2');

foreach ($articles as $article) {
    
    echo $article->getElementsByTagName('a')->item(0)->nodeValue.'
'; }

En este preciso instante, el resultado final es:

[PLMAXE] Descargar Musica y Videos Gratis Desde la Consola con Perl
Programa para Descargar Música / Gratis ? Linux y Windows SIN P2P
No se puede acceder al Twitter – Página no carga 28 sep
Como Hacer unos Anteojos para ver Videos 3D en Youtube
Iphone Llega A China con 200 mil Pedidos – Yo lo Compraba A mitad de Precio
Cambiar las Grabaciones de Ovi Maps y Ponerles tu Propia Voz [Symbian]

Si quisiésemos podríamos sacar también la Url del elemento a y poner un link al artículo o simplemente sacar todo el valor del nodo h2 y mostrarlo. Y así tendríamos los últimos posts del blog con su link respectivo.

Como podemos ver, la utilización de esta librería no tiene un límite específico... básicamente podemos explotarla hasta que nos quedemos sin ideas.

Dejo los códigos enteros para que no haya problemas a la hora de copiar y depurar.

Actividad 1:

load('http://www.w3schools.com/XML/cd_catalog.xml');

$cd = $dom->getElementsByTagName('CD');

foreach($cd as $element) {
    
    echo 'Album: '. $element->getElementsByTagName('TITLE')
                           ->item(0)
                           ->nodeValue . '
'; //Los TagName diferencian M de m.. echo 'Artista: '. $element->getElementsByTagName('ARTIST') ->item(0) ->nodeValue . '
'; echo 'Año: ' . $element->getElementsByTagName('YEAR') ->item(0) ->nodeValue . '
'; echo 'Precio: ' . $element->getElementsByTagName('PRICE') ->item(0) ->nodeValue . '

'; } //para sacar un elemento en especifico cambiamos item echo 'Album del elemento 2: '. $dom->getElementsByTagName('TITLE') ->item(1) ->nodeValue .''; //recordemos que el 0 es el 1er elemento... ?>

Actividad 2:

 'Introducción a PHP5',
                 'autor' => 'David Sklar',
                 'publicacion' => "O'Reilly"
                );
$books[] = array('title' => 'PHP Hacks',
                 'autor' => 'Jack Herrington',
                 'publicacion' => "O'Reilly"
                );

$doc = new DOMDocument();
$doc->formatOutput = true;

$r = $doc->createElement('books'); //Creamos un elemento 
$doc->appendChild($r); //lo pegamos al documento

foreach($books as $book) {
    $b = $doc->createElement("book"); //creamos un elemento 
    
    $autor = $doc->createElement("author"); //cremos elemento 
    $autor->appendChild (  //a  le pegamos el string
     $doc->createTextNode( $book['autor'])
    );
    $b->appendChild($autor); //pegamos  a 
    
    $title = $doc->createElement("title");
    $title->appendChild(
     $doc->createTextNode( $book['title'])
    );
    $b->appendChild($title);
    
    $publisher = $doc->createElement("publisher");
    $publisher->appendChild(
     $doc->createTextNode($book['publicacion'])
    );
    $b->appendChild($publisher);
    
    $r->appendChild($b);   //pegamos  a 
}

echo $doc->saveXML();

/**
 * Output:


  
    David Sklar
    Introducci󮠡 PHP5
    O'Reilly
  
  

    Jack Herrington
    PHP Hacks
    O'Reilly
  

**/
?>

Actividad 3:

loadHTML($curl); //cargamos el HTML

$primary = $doc->getElementById('primary-content');
$articles = $primary->getElementsByTagName('h2');

foreach ($articles as $article) {
    
    echo $article->getElementsByTagName('a')->item(0)->nodeValue.'
'; } function curl($web) { /** * @author Ignacio * @example curl('http://www.skamasle.com') * @param $web -> a Web Url [Forced] * @return [$data = HTML Code] */ if(! function_exists('curl_init')) $cuenta = file_get_contents($web); else { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $web); curl_setopt($curl, CURLOPT_TIMEOUT, 15); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $data = curl_exec($curl); curl_close($curl); } return $data; } ?>

5 respuestas a «Como ver, crear y editar XML y HTML en PHP con DomDocument»

  1. Ni aunque me paguen me sale hacer un post así sobre php.

    Aunque bueno, si me pagas hago todo esto para linux en bash xd

Los comentarios están cerrados.