viernes, 6 de febrero de 2009

Refactorizar el código que procesa XML, Parte 2

Refactorización del lado del cliente

Ahora como prometimos, atenderemos la cuestión del cliente. Las modificaciones se centraran en el modo de extraer y desplegar la información del documento XML. En el último ejemplo de Ajax a partir de la raíz de este documento, se extrajeron secuencialmente los valores de cada uno de los elementos que serían desplegados, almacenándolo en una serie de variables, que después eran pasadas a una función que las desplegaba agregándolas a los renglones de una tabla HTML:


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
}


Éste método resultaría en un código bastante largo si aumentara el número de elementos que serán desplegados, así que lo mejor es automatizar el proceso de extraer cada uno de los elementos del documento XML, procurando evitar los pasos secuenciales en que cae la forma anterior. Para este propósito dentro del programa Javascript se utilizará una función adicional, y además se modificara la función muestraRenglon para hacerla más compacta.

De modo que el código completo del cliente será 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>Quinto ejemplo con Ajax, combinándolo con PHP y XML (Refactorizado)</title>
<script language="javascript">
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/generaXMLConClase.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('Consulta')[0]; //Obtenemos la raíz del documento
//Accedermos al contenido de cada campo contenido en el elemento Informacion
var tabla = root.getElementsByTagName('Tabla')[0];
exploraRegistrosDeLaTabla(tabla);//Desplegamos todos los registros del elemento Tabla
}
}
}
/*Función que recibe el elemento que contiene los registros del documento XML, recorre cada uno de los
/*registros y almacena el valor de todos sus campos en el objeto objRenglon, al que después envía como
/*parámetro a la función muestraRenglon para desplegarlos en la tabla especificada
*/
function exploraRegistrosDeLaTabla(tablaXML) {
var objRenglon = new Object();
var tope1 = tablaXML.getElementsByTagName('Registro').length;
for(var i = 0; i < tope1; i++) {
registro = tablaXML.getElementsByTagName('Registro')[i];
tope2 = registro.getElementsByTagName('Campo').length;
for(var j = 0; j < tope2; j++) {
campo = registro.getElementsByTagName('Campo')[j];
objRenglon[campo.getAttribute('nombre')] = campo.firstChild.nodeValue;
}
muestraRenglon(objRenglon, 'tblInfo');
}
}
/**función que despliega un renglon dentro de la tabla HTML específicada a partir de las propiedades del
/* objeto objRenglon
*/
function muestraRenglon(objRenglon, idTabla) {
var tbody = document.getElementById(idTabla).getElementsByTagName("TBODY")[0]; //Referencia a la tabla
var renglon = document.createElement("TR"); //Crea un renglon
for(var llave in objRenglon){
var columna = document.createElement("TD"); //Crea una columna
columna.appendChild(document.createTextNode(objRenglon[llave])); //Agrega texto a la columna
renglon.appendChild(columna); //Agrega la columna al renglon
}
tbody.appendChild(renglon); //Agrega el renglon a la tabla
}
</script>
</head>
<body>
Para realizar la petición al servidor Web
<input type="button" value="presiona aqui" onclick="solicita()" />
<table id="tblInfo" cellspacing="1">
<tbody>
<tr style="background:#E1E1E1">
<td><strong>ID</strong></td>
<td><strong>Nombre</strong></td>
<td><strong>Nacionalidad</strong></td>
<td><strong>Profesión</strong></td>
</tr>
</tbody>
</table>
</body>
</html>


En ésta ocasión vemos que se hicieron unos cambios en la función procesaRespuestaXML, ya no se procesa el contenido completo del documento XML:
function procesaRespuestaXML() {
   if(peticionHttp.readyState == READY_STATE_COMPLETE) {
      if(peticionHttp.status == 200) {
         var documentoXml = peticionHttp.responseXML;
         var root = documentoXml.getElementsByTagName('Consulta')[0];
         var tabla = root.getElementsByTagName('Tabla')[0];
         exploraRegistrosDeLaTabla(tabla);
      }
   }
}

En cambio, después de acceder al elemento raíz del documento -en este caso Consulta- se crea el objeto tabla a partir del elemento Tabla, y éste es pasado como un parámetro a la función exploraRegistrosDeLaTabla, dentro de la cual se lleva todo a cabo la extracción de cada uno de los elementos que serán desplegados:
function exploraRegistrosDeLaTabla(tablaXML) {
   var objRenglon = new Object();
   var tope1 = tablaXML.getElementsByTagName('Registro').length;
   for(var i = 0; i < tope1; i++) {
      registro = tablaXML.getElementsByTagName('Registro')[i];
      tope2 = registro.getElementsByTagName('Campo').length;
      for(var j = 0; j < tope2; j++) {
         campo = registro.getElementsByTagName('Campo')[j];
         objRenglon[campo.getAttribute('nombre')] = campo.firstChild.nodeValue;
      }
      muestraRenglon(objRenglon, 'tblInfo');
   }
}


Ésta función esta formada por dos bucles for, dentro del primero se recorreran todos los elementos Registro que contenga el elemento Tabla, en el segundo bucle se recorrerán todos los elementos Campo que contenga del registro que sea accedido en el ciclo externo, almacenando los valores de cada uno de los campos en las propiedades del objeto objRenglon. Al terminar de recorrer todos los campos del registro se llamará a la función muestraRenglon, pesándole este objeto para que despliegue dentro de la tabla tblInfo un renglon que contenga los valores recogidos:
function muestraRenglon(objRenglon, idTabla) {
   var tbody = document.getElementById(idTabla).getElementsByTagName("TBODY")[0];
   var renglon = document.createElement("TR");
   for(var llave in objRenglon){
      var columna = document.createElement("TD");
      columna.appendChild(document.createTextNode(objRenglon[llave]));
      renglon.appendChild(columna);
   }
   tbody.appendChild(renglon);
}

Ésta función muestraRenglon tiene el propósito de agregar un nuevo renglón a la tabla especificada, con los valores que recibe como parámetro, solo que estos valores van contenidos dentro de las propiedades del objeto objRenglon, las cuales pueden ser extraídas como si se tratara de un arreglo asociativo dentro del bucle for de la función.

De esta forma queda finalizada la refactorización del cliente Ajax para el procesamiento de documentos XML, generados en PHP. Lo que queda en este caso es probar este nuevo programa almacenando en cliente en un archivo HTML, y guardando los archivos PHP ConsultaXML.php y generaXMLConClase.php en el directorio de páginas de nuestro servidor Web. Al probar el programa Javascript en el navegador deberemos obtener un resultado como el siguiente:



Conclusiones

El código PHP y Ajax que obtuvimos de este ejercicio nos será de gran utilidad en los ejemplos siguientes, sobre todo al momento de incursionar en el manejo de las bases de datos, al facilitarnos en gran medida el proceso de devolver el resultado de una consulta a nuestro cliente, así como el procesamiento de la información que éste lleva a cabo. El propósito de ésta práctica era contar con mejores armas para encarar los nuevos retos que nos estamos planteando, y aunque ahora puedan representa más trabajo, al adentrarse más en las aplicaciones de Ajax se verá rendir fruto a estos esfuerzos.

Hasta la próxima.

0 comentarios:

Publicar un comentario