martes, 3 de febrero de 2009

Generando una respuesta XML desde PHP


Saludos blogueros, y una disculpa porque no tuve la oportunidad de postear este fin de semana largo, pero ya estamos de vuelta para continuar con la esta serie de anotaciones sobre Ajax, ahora combinándolo con programación del lado del servidor.

En el ejemplo del último post al respecto, desde PHP se generó una respuesta en forma de contenido HTML, la cual fué recibida por una función en Javascript que desplegó este contenido directamente en la pantalla. Como se habrán dado cuenta existe una limitación en este método, y es que la respuesta consiste únicamente en texto plano, con formato HTML sí, pero cuyo único uso práctico sería desplegarse en pantalla. En uno de los ejemplos anteriores, vimos que una forma de obtener una respuesta del servidor con información estructurada, es utilizando archivos XML, cuya información puede ser procesada por una función Javascript utilizando el DOM. Ahora, como también indicamos la tecnología PHP no solo se limita a devolver contenido HTML, sino que también puede enviar una respuesta en diferentes tipos de archivos, entre ellos XML. Así, este ejemplo consistirá en programar un cliente Ajax que solicitará el archivo de un programa PHP, y esperará una respuesta XML, mientras del lado del servidor el programa PHP creará un grupo de datos, y generará un salida con éstos en forma de un archivo XML.

Para este ejemplo dejaremos un momento las obras literarias, y realizaremos una petición de información relacionada con nuestro servidor Web, solicitando los datos del navegador desde el que se realiza la petición, la información del software que utiliza el servidor Web, así como la fecha y hora del sistema operativo de este mismo servidor. La petición será procesada en PHP, y dado que la respuesta consistirá en varios datos, estos serán devueltos en formato XML, en el cual se indicarán tanto el nombre del dato que se devuelve como el valor que tienen cada uno, considerando los siguientes datos:

-Información del navegador utilizado por el usuario.
-Software del servidor Web.
-Fecha y hora del servidor Web.

El siguiente esquema puede ayudar a ilustrar el proceso completo:



Así, por medio de Ajax el cliente realizará una petición HTTP como las que ya hemos visto, solicitando el recurso http://localhost/generaXML.php. Desde el archivo generaXML.php se obtendrán los datos del servidor que se consideraron y a partir de ellos creará un documento XML, cuyo contenido será generado por medio de la función echo, utilizando previamente la función header, para indicarle al navegador que le será devuelto un archivo XML como respuesta. Este contenido será recibido por medio de Ajax como la respuesta a la petición inicial, y por medio de una función Javascript será desplegado en pantalla dentro de una tabla.

Programación del cliente

En este ejemplo, el cliente solamente contendrá un botón para iniciar la petición de la información, y la información será desplegada en una tabla HTML, una vez que se haya recibido la respuesta del servidor. El código HTML que deberemos escribir en nuestro editor de texto es el siguiente:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Cuarto ejemplo con Ajax, combinándolo con PHP y XML</title>
<script language="javascript">
<!--Sitio del código Javascript-->
</script>
</head>
<body>
Para realizar la petición al servidor Web
<input type="button" value="presiona aqui" onclick="solicita()" />
<table id="tblInfo" cellspacing="1" bordercolor="#CCCCCC">
<tr style="background:#E1E1E1"><td><strong>Dato devuelto</strong></td>
<td><strong>Valor</strong></td>
</tr>
</tbody>
</table>
</body>
</html>


Recordando que la codificación del archivo al momento de almacenarse debe ser UTF-8. En este ejemplo nuevamente colocaremos por separado el código Javascript del HTML, de forma que para probarlo solo será necesario unir ambos, colocando el siguiente código Javascript dentro del las etiquetas que se señalan:

var READY_STATE_COMPLETE=4;
var peticionHttp = null;
//Función que devuelve el objeto de la clase XMLHttpRequest
function inicializaXhr() {
   if(window.XMLHttpRequest) {
      return new XMLHttpRequest();
   }
   else if(window.ActiveXObject) {
         return new ActiveXObject("Microsoft.XMLHTTP");
   }
}
//Función que inicia todo el proceso y lleva a cabo la petición al servidor
function solicita() {
   peticionHttp = inicializaXhr();
   if(peticionHttp) {
      peticionHttp.onreadystatechange = procesaRespuestaXML;
      peticionHttp.open("POST", "http://localhost/generaXML.php", true);
      peticionHttp.send(null);
   }
}
//Función en la que se procesa el documento XML recibido
function procesaRespuestaXML() {
   if(peticionHttp.readyState == READY_STATE_COMPLETE) {
      if(peticionHttp.status == 200) {
         var documentoXml = peticionHttp.responseXML; //Creamos el objeto de tipo documento XML
         var root = documentoXml.getElementsByTagName("Informacion")[0]; //Obtenemos la raíz del documento
         //Accedermos al contenido de cada campo contenido en el elemento Informacion
         var infoCliente = root.getElementsByTagName("Cliente")[0].firstChild.nodeValue;
         muestraRenglon("Navegador",infoCliente);
         var infoSoftware = root.getElementsByTagName("Software")[0].firstChild.nodeValue;
         muestraRenglon("Software del servidor",infoSoftware);
         var infoFecha = root.getElementsByTagName("Fecha")[0].firstChild.nodeValue;
         muestraRenglon("Fecha del servidor",infoFecha);
         var infoHora = root.getElementsByTagName("Hora")[0].firstChild.nodeValue;
         muestraRenglon("Hora del servidor",infoHora);
      }
   }
}
//Función que agrega un nuevo renglon a una tabla especificada, utilizando los valores recibidos
function muestraRenglon(colEtiqueta, colValor){
   var tbody = document.getElementById('tblInfo').getElementsByTagName("TBODY")[0]; //Referencia a la tabla
   var renglon = document.createElement("TR"); //Crea un renglon
   var columna = document.createElement("TD"); //Crea una columna
   columna.appendChild(document.createTextNode(colEtiqueta)); //Agrega texto a la columna
   renglon.appendChild(columna); //Agrega la columna al renglon
   columna = document.createElement("TD"); //Crea una nueva columna
   columna.appendChild(document.createTextNode(colValor));
   renglon.appendChild(columna);
   tbody.appendChild(renglon); //Agrega el renglon a la tabla
}

Revisando el código nos damos cuenta que reutilizamos parte del código de los ejemplos anteriores para llevar a cabo una petición que se inicia con la función solicita():
function solicita() {
  peticionHttp = inicializaXhr();
  if(peticionHttp) {
    peticionHttp.onreadystatechange = procesaRespuestaXML;
    peticionHttp.open("POST", "http://localhost/generaXML.php", true);
    peticionHttp.send(null);
  }
}

Dentro de la función solicita se crea el objeto peticionHttp, y después de validar que se creo correctamente con la condición, indicamos que en cuanto se reciba la respuesta del servidor Web, se ejecute la función procesaRespuestaXML, después de lo cual realizamos la petición del recurso, en este caso identificado por la URL http://localhost/generaXML.php. Para éste ejemplo no se enviarán datos al servidor Web, lo cual indicamos pasando al método send un valor null.

En la función procesaRespuestaXML es donde se lleva a cabo el procesamiento del documento XML, que es enviado como respuesta por el servidor Web:
function procesaRespuestaXML() {
  if(peticionHttp.readyState == READY_STATE_COMPLETE) {
    if(peticionHttp.status == 200) {
      ...

Después de que validamos que se haya recido una respuesta completa, podremos pasar a procesar el documento XML.
var documentoXml = peticionHttp.responseXML;
var root = documentoXml.getElementsByTagName("Informacion")[0];

En esta dos líneas creamos el objeto documentoXML, que utilizamos para acceder al contenido del documento, y en seguida creamos el objeto root, con el que accedemos a la raíz del oducmento XML, en este caso el elemento Información. En seguida, accederemos a cada uno de los campos que encontramos dentro del elemento éste elemento, almacenando el contenido de cada campo en su respectiva variable.
var infoCliente = root.getElementsByTagName("Cliente")[0].firstChild.nodeValue;
muestraRenglon("Navegador",infoCliente);
En las dos líneas anteriores que se tomaron como referencia a este proceso, el contenido del elemento Cliente es alamacenado en la variable infoCliente, y desplegado en la página HTML dentro de la tabla tblInfo por medio de la función muestraRenglon.

La función muestraRenglon utiliza la funcionalidad que brinda el DOM del navegador, para crear objetos de tipo renglón y columna, permitiendo que se agreguen dinámicamente nuevos renglones y columnas a una tabla HTML, identificada por el id tblInfo.

De esta forma queda concluida la programación del lado del cliente para este ejemplo, pudiendo guardar este archivo HTML con cualquier nombre que nosotros deseemos, para probarlo posteriomente. Ahora, solo queda programar la aplicación PHP, que generará el documento XML de respuesta.

Programación del lado del servidor

Este pequeño programa recibirá el nombre de generaXML.php y el código que contendrá es el siguiente:

<?
header("Content-type:text/xml");
echo "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
echo "<Informacion>";
echo "<Cliente>".$_SERVER['HTTP_USER_AGENT']."</Cliente>";
echo "<Software>".$_SERVER['SERVER_SOFTWARE']."</Software>";
setlocale ( LC_TIME, 'spanish' );
echo "<Fecha>".strftime("%A %d de %B del %Y")."</Fecha>";
echo "<Hora>".strftime("%H:%M:%S")."</Hora>";
echo "</Informacion>";
?>

Al analizarlo vemos que la primer línea que aparece es la función header:
header("Content-type:text/xml");
En ésta se indica que el tipo de contenido que enviará el servidor Web como respuesta es un archivo XML, es decir que declaramos el tipo de salida que recibirá el navegador.

El resto del código consiste en realizar la creación del contenido de éste archivo XML, iniciando con:
echo "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
que es un encabezado que declara la versión de XML que estamos utilizando, así como la codificación de los caracteres utilizada, en este caso utf-8. El resto del código crea cada uno de los elementos del documento XML, que representarán los campos con la información que desde un inicio teniamos pensado solicitar al servidor Web, y cada uno de ellos corresponde a los elementos que será accedido desde Javascript en el cliente.

Al almacenar el archivo PHP en el servidor Web podemos pasar a la prueba, si seguimos cada uno de los pasos indicados aquí, la respuesta que obtendremos será similar a esta:



Conclusiones

El punto central de este ejercicio es demostrar como desde PHP se puede mandar un conjunto de datos en XML, y procesarlos en Javascript pudiendo discriminarlo para desplegarlos de manera que se respete la estructura original. Esta práctica es importante porque utilizando los mismos principios, es posible mandar información estructurada en mayores volumnes ,desde el servidor hasta el programa cliente en Javascript. Se pondrían mandar, por ejemplo una serie de registros que representen los renglones de una tabla en una base de datos, o que representen una serie de mensajes generados que describan el resultado de un proceso que ocurrió en el servidor. Entonces, debido a la utilidad que representan las respuestas XML desde el servidor, este será el estándar que utilizaremos para entregar las respuestas a nuestros clientes Ajax, en los ejemplos que seguirán de ahora en adelante.

En los siguientes post veremos como refactorizar el código tanto del cliente como del servidor para automatizar más el manejo de XML, además haremos una introducción al manejo de bases de datos combinando Ajax con PHP.

Hasta la próxima.

0 comentarios:

Publicar un comentario