Programación Hipermedia I

Práctica 12: PHP 7 (DOM)

1. Objetivos

2. Recursos

¿Qué es el DOM?

¿Cómo puedo manejar el DOM desde PHP?

¿Cómo puedo comprobar que el formato de mi canal web es correcto?

3. ¿Qué tengo que hacer?

En esta práctica tienes que crear una fuente o canal web (feed), con formatos RSS 2.0 y Atom, donde se muestren los datos de las últimas cinco fotos publicadas. Este canal web recibirá un parámetro que indicará el formato deseado (RSS o Atom). Para crear el canal web se tiene que emplear el DOM de PHP y se tienen que crear y manipular los nodos (no vale crear el documento de salida a partir de una cadena).

4. ¿Cómo lo hago?

Una fuente o canal web (feed) es un mecanismo que permite la redifusión del contenido web. Un canal web permite suministrar información actualizada frecuentemente a los usuarios, llamados suscriptores. Mediante un programa compatible con un canal web, un suscriptor puede recibir una alerta cuando se produzca una actualización en el canal web (y por tanto, en el sitio web de origen de los contenidos).

Existen varios formatos de redifusión de contenido, pero los dos más utilizados son RSS y Atom. Ambos formatos utilizan el lenguaje XML y se suelen identificar en una página web con el icono que aparece en la Figura 1.

Un canal web contiene una lista de las últimas actualizaciones, llamadas entradas. Normalmente, cada entrada tiene un título, un enlace para ampliar información, una descripción o resumen del contenido de la entrada y una fecha de publicación.

El DOM (Document Object Model) es una API destinada a trabajar con documentos HTML y XML. El DOM está desarrollado por el W3C.

El DOM proporciona una representación en forma de árbol de un documento y permite su manipulación (añadir un elemento nuevo, borrar un elemento, mover un elemento de sitio).


PIC


Figura 1: Logotipo de una fuente o canal web


PHP 5 posee la extensión DOM que permite manipular documentos HTML y XML. Esta extensión está instalada y configurada por defecto, por lo que en una instalación estándar no es necesario hacer nada especial para usarla.

La extensión DOM de PHP proporciona un conjunto de clases que representan diferentes partes de un documento HTML o XML. Las clases más importantes con algunos de sus métodos son:

Un nodo (DOMNode) posee la propiedad nodeType que define el tipo de nodo. En el Cuadro 1 se muestran las constantes con sus respectivos valores para cada tipo de nodo.





Constante ValorTipo de nodo



XML_ELEMENT_NODE 1 DOMElement



XML_ATTRIBUTE_NODE 2 DOMAttr



XML_TEXT_NODE 3 DOMText



XML_CDATA_SECTION_NODE 4 DOMCharacterData



XML_ENTITY_REF_NODE 5 DOMEntityReference



XML_ENTITY_NODE 6 DOMEntity



XML_PI_NODE 7 DOMProcessingInstruction



XML_COMMENT_NODE 8 DOMComment



XML_DOCUMENT_NODE 9 DOMDocument



XML_DOCUMENT_TYPE_NODE10 DOMDocumentType



XML_DOCUMENT_FRAG_NODE11 DOMDocumentFragment



XML_NOTATION_NODE 12 DOMNotation




Cuadro 1: Constantes XML de tipo de nodo

Existen clases específicas para representar los diferentes tipos de nodos: DOMComment, DOMElement, DOMText, etc.

El siguiente ejemplo muestra cómo crear un documento HTML nodo a nodo. Para ello se proporciona la clase HTMLDocument que ofrece varios métodos para crear el contenido de una página web: addHead(), addBody(), addStyleSheet(), addScript(), addMetaTag(), etc. El método generate() genera la página web resultante en forma de cadena. La clase HTMLDocument permite generar páginas web con el DOCTYPE XHTML 1.0 Strict o HTML 5.

<?php 
class HTMLDocument { 
   private $doctype; 
   private $lang; 
   private $head; 
   private $title; 
   private $body; 
   private $styles; 
   private $metas; 
   private $scripts; 
   private $document; 
 
   public function __construct($doctype = html5’, $title = ’’, $lang = es’) { 
      $implementation = new DOMImplementation(); 
 
      switch($doctype) { 
         default: 
         case html5’: 
            $dtd = $implementation->createDocumentType(’html’); 
            break; 
 
         case xstrict’: 
            $dtd = $implementation->createDocumentType(’html’, 
                     ’-//W3C//DTD XHTML 1.0 Strict//EN’, 
                     http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd’); 
            break; 
      } 
 
      $this->document = $implementation->createDocument(’’, ’’, $dtd); 
      $this->lang = $lang; 
      $this->doctype = $doctype; 
      $this->title = $title; 
   } 
 
   public function addHead($element) { 
      $this->head[] = $element; 
   } 
 
   public function addBody($element) { 
      $this->body[] = $element; 
   } 
 
   public function addStyleSheet($url, $media = all’) { 
      $element = $this->document->createElement(’link’); 
      $element->setAttribute(’rel’, stylesheet’); 
      $element->setAttribute(’href’, $url); 
      $element->setAttribute(’type’, text/css’); 
      $element->setAttribute(’media’, $media); 
      $this->styles[] = $element; 
   } 
 
   public function addScript($url) { 
      $element = $this->document->createElement(’script’, ’’); 
      $element->setAttribute(’src’, $url); 
      $element->setAttribute(’type’, text/javascript’); 
      $this->scripts[] = $element; 
   } 
 
   public function addMetaTag($name, $content) { 
      $element = $this->document->createElement(’meta’); 
      $element->setAttribute(’name’, $name); 
      $element->setAttribute(’content’, $content); 
      $this->metas[] = $element; 
   } 
 
   public function setTitle($title) { 
      $this->title = $title; 
   } 
 
   public function setAuthor($author) { 
      $this->addMetaTag(’author’, $author); 
   } 
 
   public function setDescription($description) { 
      $this->addMetaTag(’description’, $description); 
   } 
 
   public function setKeywords($keywords) { 
      $this->addMetaTag(’keywords’, $keywords); 
   } 
 
   public function createElement ($nodeName, $nodeValue = NULL) { 
      return $this->document->createElement($nodeName, $nodeValue); 
   } 
 
   public function generate() { 
      $html = $this->document->createElement(’html’); 
      $html->setAttribute(’lang’, $this->lang); 
      switch($this->doctype) { 
         case xstrict’: 
            $html->setAttribute(’xmlns’, http://www.w3.org/1999/xhtml’); 
            $html->setAttribute(’xml:lang’, $this->lang); 
            break; 
      } 
      $this->document->appendChild($html); 
 
      $head = $this->document->createElement(’head’, ’’); 
      $title = $this->document->createElement(’title’, $this->title); 
      $head->appendChild($title); 
 
      if(is_array($this->metas)) { 
         foreach($this->metas as $element) { 
            $head->appendChild($element); 
         } 
      } 
      if(is_array($this->styles)) { 
         foreach($this->styles as $element) { 
            $head->appendChild($element); 
         } 
      } 
      if(is_array($this->scripts)) { 
         foreach($this->scripts as $element) { 
            $head->appendChild($element); 
         } 
      } 
      if(is_array($this->head)) { 
         foreach($this->head as $element) { 
            $head->appendChild($element); 
         } 
      } 
      $html->appendChild($head); 
 
      $body = $this->document->createElement(’body’, ’’); 
      if(is_array($this->body)) { 
         foreach($this->body as $element) { 
            $body->appendChild($element); 
         } 
      } 
      $html->appendChild($body); 
 
      switch($this->doctype) { 
         default: 
         case html5’: 
            $result = $this->document->saveHTML(); 
            break; 
 
         case xstrict’: 
            $result = $this->document->saveXML(); 
            break; 
      } 
 
      return $result; 
   } 
} 
 
// $document = new HTMLDocument("html5", "Esto es una prueba"); 
$document = new HTMLDocument("xstrict", "Esto es una prueba"); 
$document->addStyleSheet("estilo.css"); 
$document->addScript("codigo.js"); 
$document->setAuthor(utf8_encode("Sergio Luján Mora")); 
$document->setDescription(utf8_encode("Una página web de prueba")); 
 
$div1 = $document->createElement(’div’); 
$div1->nodeValue = Esto es un texto escrito en rojo.’; 
$div1->setAttribute(’style’, color: red;’); 
$document->addBody($div1); 
 
$div2 = $document->createElement(’div’); 
$div2->nodeValue = Esto es un texto escrito en verde.’; 
$div2->setAttribute(’style’, color: green;’); 
$document->addBody($div2); 
 
echo $document->generate(); 
?>

En el código anterior se ha usado la clase DOMImplementation para poder definir el DOCTYPE del documento que se genera, ya que la clase DOMDocument no ofrece un mecanismo para definirlo.

¡Mucho cuidado! La extensión DOM de PHP utiliza internamente la codificación UTF-8. Si la página PHP utiliza otra codificación, se tiene que hacer una conversión en la codificación de los caracteres. En el ejemplo anterior, como el código está escrito con la codificación ISO-8859-1, se ha usado la función utf8_encode() para realizar la conversión en aquellos casos en los que ha sido necesario (por ejemplo, cuando aparece una vocal acentuada).

¡Mucho cuidado! Un nodo sólo puede añadirse al documento a partir del cual ha sido creado, si se añade a otro documento se produce un error. Por ejemplo, en el siguiente código se crean dos dos a partir de dos documentos y posteriormente se añaden al documento opuesto:

<?php 
      $d1 = new DOMDocument(); 
      $d2 = new DOMDocument(); 
 
      $e1 = $d1->createElement("aaa"); 
      $d1->appendChild($e1); 
 
      $e2 = $d2->createElement("bbb"); 
      $d2->appendChild($e2); 
 
      $d1->appendChild($e2); 
      $d2->appendChild($e1); 
?>

El ejemplo anterior produce el siguiente mensaje de error:

Fatal error: Uncaught exception DOMException with message Wrong Document Error in 
C:\Users\Sergio\Dropbox\htdocs\practicas\prueba.php:11 
Stack trace: 
#0 C:\Users\Sergio\Dropbox\htdocs\practicas\prueba.php(11): 
DOMNode->appendChild(Object(DOMElement)) 
#1 {main} 
 thrown in C:\Users\Sergio\Dropbox\htdocs\practicas\prueba.php on line 11

Si se quiere copiar un nodo de un documento a otro, se tiene que clonar e importar.

5. Recomendaciones

Crear un documento XML es muy sencillo con el DOM si se tiene clara la estructura del documento que se quiere crear. El primer paso es construir el documento con “papel y lápiz”.

Puedes usar el validador Feed Validation Service4 del W3C para comprobar que el formato del canal web es correcto.

1http://www.w3.org/DOM/

2http://php.net/manual/es/book.dom.php

3http://validator.w3.org/feed/

4http://validator.w3.org/feed/