lunes, 16 de agosto de 2010

0006 Ajax – PHP – PostgreSQL II



En este segundo tutorial sobre AJAX – PHP – PostgreSQL se van a tratar los siguientes puntos:

  1. Mostrar el contenido de la página "index.html" dependiendo de un parámetro seleccionado por el usuario.

  2. Enviar un parámetro a través de AJAX al script de PHP por medio de POST.

  3. Guardar el resultado de la consulta SQL en formato XML y leer el contenido del resultado mediante AJAX.

  4. Leer etiquetas HTML contenidos en el XML resultante.
  5. Leer caracteres especiales HTML, (á, é, í, ó, ú), contenidos en el archivo XML dentro de los etiquetas HTML.
Código de la tabla ajax:
 CREATE TABLE ajax  
   
 (  
   
 id serial NOT NULL,  
   
 nombre character varying(50),  
   
 apellido character varying,  
   
 cedula character varying(8),  
   
 sexo boolean,  
   
 CONSTRAINT pid PRIMARY KEY (id)  
   
 )  
   
 WITH (  
   
 OIDS=FALSE  
   
 );  
   
 ALTER TABLE ajax OWNER TO postgres;  
   
   
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (1, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (2, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (3, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (4, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (5, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (6, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (7, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (8, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (9, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (10, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (11, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (12, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (13, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (14, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (15, 'David', 'Lastra', '14852152', true);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (16, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (17, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (18, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (19, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (20, 'Miss', 'Universo', '11111111', false);  
   
 INSERT INTO ajax (id, nombre, apellido, cedula, sexo) VALUES (21, 'Miss', 'Universo', '11111111', false);  
La primera parte consta de la creación de la tabla con el nombre de "ajax" en minúsculas. La segunda parte es la inserción de datos para trabajar con los mismos desde los scripts.

Código index.html:
 <!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>Prueba de [ AJAX - PHP - POSTGRESQL II]</title>  
  <script language="javascript" src="js/ajax.js" type="application/javascript"></script>  
 </head>  
 <body style="background-color:#366;">  
 <table border="0" style="color:white; background-color:#000;" align="center">  
 <tr>  
 <td colspan="2" align="center">  
 <strong>Prueba de:</strong><span style="color:#F00; font-weight:bolder;">[ AJAX - PHP - POSTGRESQL II]</span>  
 </td>  
 </tr>  
 <tr>  
 <td colspan="2">  
      <div id="contenido" style="color:#1FE4EF; font-family:'Times New Roman', Times, serif;"></div>  
 </td>  
 </tr>  
 <tr>  
 <td align="center">  
 <form action="#" name="frmSexo">  
 <select name="sexo"><option value="true" >Hombre</option><option value="false">Mujer</option></select>  
 </form>  
 <hr />  
      <a href="#" onclick="javascript:fDatos('contenido',frmSexo.sexo.options[frmSexo.sexo.selectedIndex].value ,'ajax.php');" style="color:#0F0; text-decoration:none;">[ Mostrar datos ]</a>  
 </td>  
 <td align="center">  
      <a href="#" onclick="javascript:fBorrar('contenido');" style="color:#F00; text-decoration:none;">[ Limpiar contenido ]</a>  
 </td>  
 </tr>  
 </table>  
 </body>  
 </html>  
Las etiquetas HTML más importantes que se muestran arriba están resaltadas en colores.

  1. <script language>: para indicar donde se encuentra el archivo javascript con las funciones a usar.
  2. <div id="contenido">: el contenido de este div es el que se va a modificar por medio de las funciones "fDatos" y "fBorrar" de javascript.
  3. <form name="frmSexo">: formulario con un campo select para seleccionar los datos de las personas de la tabla "ajax" según el sexo.
  4. <a href="#" onclick="javascript:fDatos>: Al hacer "click" en éste link se inicia el proceso para la carga de datos mediante AJAX en el DIV correspondiente.
  5. <a href="#" onclick="javascript:fBorrar>: Al hacer "click" en éste link se borra el contenido del DIV.
  6. fDatos('contenido',frmSexo.sexo.options[frmSexo.sexo.selectedIndex].value ,'ajax.php');:
    1. fDatos: nombre de la función javascript.
    2. 'contenido': nombre de la etiqueta DIV donde se va a modificar el contenido.
    3. frmSexo.sexo.options[].value: El valor seleccionado por el usuario en el menú desplegable, (frmSexo.sexo.options à es un array para poder acceder a los posibles valores), los posibles valores para este caso son: true - "Hombre", false – "Mujer".
    4. frmSexo.sexo.selectedIndex: Sirve para indicar cuál es la opción actualmente seleccionada por el usuario. El valor seleccionado del menú desplegable, (0 - true, 1 - false).
    5. frmSexo.sexo.options[ frmSexo.sexo.selectedIndex ].value = true o false.
  7. fBorrar('contenido'): Función que se encarga de borrar el contenido al DIV seleccionado.
Código ajax.js:
1:  /*------------------------------------------------------*/  
2:  //Función para crear el objeto Ajax.          //  
3:  /*------------------------------------------------------*/  
4:  function nuevoAjax()  
5:  {  
6:   var xmlhttp=false;  
7:   try  
8:   {  
9:    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");  
10:   }  
11:   catch (e)  
12:   {  
13:    try  
14:    {  
15:     xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");  
16:    }  
17:    catch (e)  
18:    {  
19:     xmlhttp = false;  
20:    }  
21:   }  
22:   if (!xmlhttp && typeof XMLHttpRequest!='undefined')  
23:   {  
24:    xmlhttp = new XMLHttpRequest();  
25:   }  
26:   return xmlhttp;  
27:  }  
28:  /*------------------------------------------------------*/  
29:  //id: id del control div que va a recibir los datos.  //  
30:  //sexo: verdadero o falso, filtro booleando para la   //  
31:  //carga de datos según el campo sexo.          //  
32:  //url: Dirección url de la página donde se       //  
33:  //obtiene los datos.                  //  
34:  /*------------------------------------------------------*/  
35:  function fDatos(id, sexo, url)  
36:  {  
37:   var objDiv = document.getElementById(id);  
38:   var objXML = null;  
39:   var objTBL = null;  
40:   if (sexo == 'true')  
41:    sexo = true;  
42:   else  
43:    sexo = false;  
44:   ajax = nuevoAjax();  
45:   ajax.open("POST", url, true);  
46:   ajax.onreadystatechange = function()  
47:   {  
48:    switch (ajax.readyState)  
49:    {  
50:    case 0:  
51:     objDiv.innerHTML = 'Error 0. No se ha abierto la comunicaci&oacute;n.';  
52:     break;  
53:    case 1:  
54:     objDiv.innerHTML = 'Por favor, espere. Cargando...';  
55:     break;  
56:    case 2:  
57:     objDiv.innerHTML = 'Petici&oacute;n cargada, esperando respuesta del servidor...';  
58:     break;  
59:    case 3:  
60:     objDiv.innerHTML = '';  
61:     break;  
62:    case 4:  
63:     if(ajax.status == 200)  
64:     {  
65:       try  
66:       {  
67:       objDiv.innerHTML = "Datos a mostrar... <hr />";  
68:       objXML = ajax.responseXML;  
69:       objTBL = objXML.getElementsByTagName('tabla');  
70:       objDiv.innerHTML += objTBL[0].firstChild.nodeValue;  
71:       objDiv.innerHTML += "<hr />";  
72:       }  
73:       catch (e)  
74:       {  
75:        objDiv.innerHTML += e.toString() + " Error al recibir datos de archivo XML...";  
76:       }  
77:     }  
78:     else  
79:     {  
80:       objDiv.innerHTML = 'Error 200';  
81:     }  
82:     break;  
83:    }  
84:   }  
85:   ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");  
86:   ajax.send("sexo="+sexo);  
87:  }  
88:  /*------------------------------------------------------*/  
89:  //Borrar los datos de la celda en la página web...   //  
90:  /*------------------------------------------------------*/  
91:  function fBorrar(id)  
92:  {  
93:   document.getElementById(id).innerHTML = "";  
94:  }  
  1. Función nuevoAjax: Se encarga de crear el objeto AJAX para poder hacer la carga de datos de forma asincrónica.
  2. Función fDatos:
    1. Id = id del objeto DIV que se va a manipular.
    2. Sexo = booleano, filtro para obtener datos según la selección hecha por el usuario mediante el control SELECT del formulario de la página "index.html".
    3. url = página que se va a llamar para obtener los datos deseados mediante AJAX, en este caso la página a llamar es "ajax.php".
    4. El valor de los parámetros es colocado en la llamada a la función fDatos en la página de "index.html".
    5. objXML = ajax.responseXML;: Indica que el tipo de respuesta vendrá en formato XML.
    6. objTBL = objXML.getElementsByTagName('tabla');: Se asigna a la variable objTBL el contenido de la etiqueta "tabla" del archivo XML. "objTBL" es un array del tamaño de todas las etiquetas con el nombre "tabla" que existan en el archivo XML. (En el siguiente apartado se verá el contenido del archivo XML).
    7. objDiv.innerHTML += objTBL[0].firstChild.nodeValue;: Se accede al valor del primer elemento de la variable "objTBL" y se muestra en la etiqueta DIV correspondiente, para este caso 'contenido'.
    8. ajax.send("sexo="+sexo);: En el método "send" del objeto "ajax" se introduce el parámetro que se va a enviar al script "ajax.php". En el caso de que se quiera enviar más parámetros, la cadena de construcción queda con el siguiente formato: [ajax.send("nomvar1="+valvar1+"&nomvar2="+valvar2+"&nomvar3="+valvar3 + … +"&nomvarN="+valvarN)]. Hay que usar el carácter "&" para concatenar las variables.
    9. "nomvar" acrónimo de nombre de variable. "valvar" acrónimo de valor de variable.
  3. Función fBorrar: Se encarga de limpiar el contenido de la etiqueta DIV.
Código ajax.php:
1:  <?php  
2:  $conbd = pg_connect("host=localhost port=5432 dbname=prueba user=tuusuario password=tucontraseña") or die(pg_last_error());  
3:  $sql = "SELECT id, nombre, apellido, cedula FROM ajax WHERE sexo = " . $_POST['sexo'] . ";";  
4:  $res = pg_query($conbd, $sql);  
5:  if($res)  
6:  {  
7:  if(pg_num_rows($res)>0)  
8:  {  
9:  header("Content-Type: text/xml");  
10:  $xml = "<?xml version='1.0' encoding='ISO-8859-1' ?>\n";  
11:  $xml .= "<datos>\n";  
12:  $xml .= "<tablas>\n";  
13:  $xml .= "<tabla>";  
14:  $xml .= "<!--<table border=\"1\">\n";  
15:  $xml .= "<tr>\n";  
16:  $xml .= "<td align=\"center\"> [ ID ]      </td>\n";  
17:  $xml .= "<td align=\"center\"> [ NOMBRE ]    </td>\n";  
18:  $xml .= "<td align=\"center\"> [ APELLIDO ]   </td>\n";  
19:  $xml .= "<td align=\"center\"> [ C&#201;DULA ] </td>\n";  
20:  $xml .= "</tr>\n";  
21:  while($val = pg_fetch_array($res))  
22:  {  
23:  $xml .= "<tr><td>" . $val[0] . "</td><td>" . $val[1] . "</td><td>" . $val[2] . "</td><td>" . $val[3] . "</td></tr>\n";  
24:  }  
25:  $xml .= "</table>-->";  
26:  $xml .= "</tabla>\n";  
27:  $xml .= "</tablas>\n";  
28:  $xml .= "</datos>\n";  
29:  echo $xml; //escribe, en resultado, un archivo XML con los datos obtenidos mediante la consulta…  
30:  }  
31:  pg_free_result($res);  
32:  }  
33:  pg_close($conbd);  
34:  ?>  

En el script "ajax.php" es donde se va a crear el contenido XML con los datos que se obtienen de la consulta SQL. Se describe, a continuación, los pasos del script "ajax.php":
  1. Cadena de conexión para acceder a la base de datos con el nombre de "prueba", ($conbd: ID de conexión).
  2. Cadena de consulta que tiene por filtro la variable "sexo" que viene por POST desde AJAX y se ejecuta sobre la tabla "ajax", ($sql - $_POST['sexo']).
  3. Ejecución de la consulta, ($res = pg_query($conbd, $sql);).
  4. Si la consulta es correcta, entonces…
  5. Si la consulta ha traído más de 0 filas entonces…
  6. Se define la cabecera del archivo con el comando "header". "Content-Type: text/xml", define los datos que siguen como contenido XML.
  7. La primera línea del archivo XML define la versión y la codificación de caracteres.
  8. Primera etiqueta: <datos>\n.
  9. Segunda etiqueta: <tablas>\n.
  10. Tercera etiqueta: <tabla> + código embebido HTML (Siguiente punto a explicar) + </tabla>\n.
  11. Cerrar segunda etiqueta: </tablas>\n.
  12. Cerrar primera etiqueta: </datos>.
  13. echo $xml;: Mostrar el resultado.
  14. Limpiar la consulta, (pg_free_result($res);).
  15. Cerrar la conexión a la base de datos, (pg_close($conbd);).
Código embebido HTML:
El código HTML del script "ajax.php" está embebido en el XML resultante del script "ajax.php". Para que se puedan interpretar los tags HTML, el HTML embebido debe empezar como si se tratase como un comentario, como se muestra a continuación: <!—Introducir código HTML aquí. -->. Esto permite la distinción entre las etiquetas XML y las etiquetas HTML.
Todos las etiquetas HTML entre de "<!--" y "-->" serán ignorados como etiquetas XML pero no como etiquetas HTML, lo que permite recuperar el contenido HTML sin que entre en conflicto con las etiquetas XML. Es muy importante que se tenga presente lo siguiente: XML no puede leer, distinguir ni interpretar código HTML, si dentro de un archivo XML se encuentra una etiqueta HTML como por ejemplo "<br>" o "<table>", XML lo tomará como parte del formato del documento, no como una etiqueta HTML.
  1. "<!--<table border=\"1\">\n";: Inicio del comentario XML e inicio de la etiqueta <table> para definir la tabla con los resultados a mostrar.
  2. "<tr>\n";: Inicio de la primera fila que contiene la cabecera de la tabla.
  3. "<td align=\"center\">[ ID ]</td>\n";: Celda ID.
  4. "<td align=\"center\">[ NOMBRE ]</td>\n";: Celda Nombre.
  5. "<td align=\"center\">[ APELLIDO ]</td>\n";: Celda Apellido.
  6. "<td align=\"center\">[ C&#201;DULA ]</td>\n";: Celda Cédula.
  7. "</tr>\n";: Fin de la cabecera.
  8. while($val = pg_fetch_array($res)): Bucle para obtener todas las filas devueltas por la consulta.
  9. "<tr><td>" . $val[0] . "</td><td>" . $val[1] . "</td><td>" . $val[2] . "</td><td>" . $val[3] . "</td></tr>\n";: Fila y celdas con los datos obtenidos de la consulta.
  10. "</table>-->";: Cierre del tag HTML "</table>" y cierre de la línea de comentario XML "-->".
A continuación se muestra como se vería el XML resultante, desde mozilla firefox, al ejecutar el script "ajax.php" con el parámetro "true" en la consulta SQL.

1:  <?xml version="1.0" encoding="ISO-8859-1"?>  
2:  <datos>  
3:  <tablas>  
4:  <tabla><!--<table border="1">  
5:  <tr>  
6:  <td align="center"> [ ID ]      </td>  
7:  <td align="center"> [ NOMBRE ]    </td>  
8:  <td align="center"> [ APELLIDO ]   </td>  
9:  <td align="center"> [ C&#201;DULA ] </td>  
10:  </tr>  
11:  <tr><td>1</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
12:  <tr><td>2</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
13:  <tr><td>3</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
14:  <tr><td>4</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
15:  <tr><td>5</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
16:  <tr><td>12</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
17:  <tr><td>13</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
18:  <tr><td>14</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
19:  <tr><td>15</td><td>David</td><td>Lastra</td><td>14852152</td></tr>  
20:  </table>--></tabla>  
21:  </tablas>  
22:  </datos>  

Caracteres especiales HTML:
Dentro de las etiquetas XML se pueden encontrar fallos a la hora de usar entidades por nombre para visualizar caracteres especiales HTML, la solución pasa por usar su equivalente entidad numérica.
Si hay errores al visualizar caracteres especiales HTML dentro de las etiquetas XML como entidades por nombre, "&aacute;", siempre se puede recurrir a su equivalente entidad numérica. Por ejemplo, la palabra "Cédula" en HTML se podría escribir de la siguiente manera "C&eacute;dula", pero, con la codificación de caracteres actual "&eacute;" no funciona dentro del XML, para solucionar este inconveniente se puede recurrir a su entidad numérica "&#201;" y quedaría de la siguiente manera "C&#201;dula".
Usando la correspondiente entidad numérica se puede solventar los fallos de interpretación de las entidades por nombre de las etiquetas HTML en el contenido XML.
A continuación adjunto el link con las tablas de conversiones entre entidades por nombre y su correspondencia a entidades numéricas: Tablas de conversión
Resumen:
En este artículo se han cubierto los siguientes puntos:
  • Paso de parámetros desde AJAX por POST a PHP usando el método "send".
  • Según el parámetro seleccionado el contenido a mostrar cambia dentro de la página HTML.
  • Lectura HTML embebido en XML por medio de javascript.
  • Guardar el resultado obtenido en la consulta SQL a formato XML.
  • Interpretar caracteres especiales HTML embebidos en XML mediante el uso de entidades numéricas en el caso de que falle la interpretación de entidades por nombre.
Si tienen alguna duda o algo constructivo que añadir, pueden dejar un comentario o enviarme un e-mail.
Un cordial saludo.
Firma: XDRTAS

2 comentarios:

George dijo...

Muy buenas tardes, estoy aplicando el manual al pie de la letra, pero cuando abro el navegador y doy clic en Mostrar Datos me da el error:

"TypeError: Cannot call method 'getElementsByTagName' of null"

Te agradeceria cualquier ayuda!!

Unknown dijo...

Hola Jorge, para asegurarme, realicé todo el procedimiento paso a paso copiando todo desde la página y me ha funcionado, aunque me dí cuenta que no coloqué la estructura de directorios y a ver si va a ser por ahí el fallo, te adjunto como debería quedar la estructura:
(1).-ajax - (carpeta principal)
(1.1).- js - (subcarpeta que contiene el archivo ajax.js)
(1.2).-ajax.php - Archivo con el código php
(1.3).-index.html - Archivo HTML que contiene la referencia al archivo ajax.js

Otra opción, que es la más probable, es que sencillamente está mal escrito el tag dentro de tu archivo php o js, o también, está duplicado el nombre del tag. Si te fijas bien, hay tres tags parecidos:
1.-< tablas >: Plural
2.-< tabla >: Singular. objXML.getElementsByTagName('tabla'); -> Como puedes observar, aquí es donde tienen que coincidir los nombres entre el ajax.js y el ajax.php.
3.- < !--< table border=\"1\" > - comando HMTL
Asegúrate de las tres etiquetas contengan distintos nombres.

Espero que lo puedas resolver,
Un cordial saludo.