Mostrando entradas con la etiqueta HTML. Mostrar todas las entradas
Mostrando entradas con la etiqueta HTML. Mostrar todas las entradas

sábado, junio 27, 2009

Sistema de plugins en C# usando Reflexión

En este post os voy a describir un pequeño sistema de plugins que implementé para un proyecto y que me resultó de mucha utilidad y sobre todo, me permitió aumentar el sistema sin tener que cambiar nada de lo ya establecido (códigos, recompilaciones, etc.).

La idea es disponer de un sistema de plugins para un CMS (gestor de contenidos) de forma que cada plugin sea autogestionado y no haya que tocar nada del sistema a la hora de introducir un nuevo plugin, salvo lógicamente introducir su definición en base de datos. En el proyecto que implementé, los plugins eran elementos visuales que permitían realizar la maquetación de las páginas mostrando el contenido de base de datos de diferentes formas (contenido tabulado, histórico, contenido con scroll, publicidad, etc.).



No voy a entrar en cómo implementar toda la estructura del sistema de elementos visuales (será para un artículo posterior), lo importante es cómo podemos, acceder a clases de c# sin utilizar elementos tipados. Es decir, lo normal para instanciar un objeto es utilizar la siguiente nomenclatura:

TipoObjeto miObjeto = new TipoObjeto(parametros);

En el caso de un sistema dinámico de plugins, no podemos utilizar esa nomenclatura porque no sabemos a priori la clase del objeto a utilizar. En esta situación, la reflexión se nos ofrece como técnica perfecta.

Implementación del sistema de plugins

Los plugins se dan de alta en base de datos, cada proyecto puede utilizar su propia definición de tablas. En mi caso, creé dos tablas, una para guardar la definición del elemento y otra para almacenar las propiedades modificables del elemento. Por ejemplo, uno de los plugins era para introducir un bloque de código HTML directamente en la página. La definición de este elemento es:


y la definición de sus propiedades es:


Lo importante de los datos almacenados para cada elemento es el campo "clase" en el que se guarda la clase de código que implementa la funcionalidad de este elemento. En este caso, la clase es plugins.elementoHtml. Este campo se utiliza luego para la reflexión.

Interfaz de los plugins
Este paso no es necesario pero es bueno que todas las clases que se encarguen de plugin implementen una interfaz obligando a que el método público de acceso sea siempre igual y no haya fallos de parámetros. En mi caso, la interfaz definía los siguientes métodos:

La interfaz define dos métodos, uno para obtener el código html del plugin cuando se debe insertar en el centro de la página y otro para cuando se debe insertar en el lateral de la página. Los parámetros que se pasan son el id particular para cada elemento y un object extras con parámetros extras que hicieran falta en cada caso.

El quid de la cuestión

En cada proyecto, obtendremos referencias a nuestros plugins de la manera que queramos. El quid de la cuestión se encuentra en las líneas que utilizan la reflexión para acceder a los métodos de la clase de cada plugin:




Lo que hacemos es:
  1. Obtener el campo "clase" de la base de datos y llamar al método Type.GetType para obtener el tipo del elemento.
  2. A través de reflexión podemos obtener acceso al constructor e invocarlo pasándole los argumentos necesarios, en este caso null porque no hay argumentos.
  3. Obtener la información del método "Renderizar" que es el que utilizamos de cada clase y que define la interfaz.
  4. Invocamos el método pasándole el objeto inicializado mediante el constructor y le pasamos un vector de objects con los parámetros que el método está esperando.
  5. El resultado del método (en este caso un string), se obtiene haciendo un cast a string.
Conclusión
La reflexión es una herramienta muy potente dentro del lenguaje .net que permite llamar a métodos y objetos sin conocer previamente el tipo. Esto permite generar sistemas como el descrito de una forma eficiente. El problema estriba en que, inicialmente no es un tipo de programación sencilla y requiere un tiempo para acostumbrarse a cómo funciona.

Espero que os haya gustado este artículo y que os sirva esta idea para vuestros desarrollos. En mi caso, me ha sido de mucha utilidad.




jueves, julio 12, 2007

Frameworks para RIAs

En esta cuarta entrega del desarrollo basado en Ajax, nos vamos a centrar en los diferentes frameworks existentes que nos pueden ayudar en nuestros desarrollos. Si no os habéis leído los posts anteriores, os recomiendo que os los leáis para entender mejor este:
En este post vamos a ver diferentes alternativas de las que disponemos para agilizar nuestra tarea (otra gente se ha pegado con el teclado por nosotros). Vamos a ver, aunque existen muchísimos más, los siguientes:
  • YUI: Yahoo User Interface, framework de Yahoo (que listo soy) para aplicaciones ricas de internet (RIA: Rich Internet Application). Muy completo y con un montón de ejemplos y documentación.
  • Dojo: Framework de la Dojo Foundation. Es también muy completo, quizás un poco más sencillo de utilizar que el de Yahoo y menos pesado para el explorador, aunque con menos documentación.
  • GWT: Google Web Toolkit. Es la implementación que da Google para Ajax sobre Java. En realidad, la filosofía de GWT es la de programar en Java y él interpreta el código Java para generar las páginas con los controles AJAX.
  • AJAX ASP.NET: La implementación para asp.net de AJAX. Incluye, aparte del core de librerías de comunicación una librería de controles llamada Atlas Control Toolkit. Se puede utilizar aunque no se utilice asp.net.
Todas estas librerías son de libre distribución. Por supuesto, existen muchas librerías de pago con controles flipantes que casi te programan la aplicación solas, pero los currelas de a pié, nos conformaremos con éstas (de hecho son muy buenas todas). Personalmente, la que más uso (todos los días) es la de ASP.NET, que hace cosas muy chulas. Tened en cuenta que en lo que más dan estos frameworks son controles para hacer nuestras aplicaciones más interactivas. Pero, vamos al tajo:

Yahoo User Interface:
Esta fue la primera librería que utilicé en mis pruebas. Tiene varias cosas muy buenas a tener en cuenta:
  • Una documentación muy buena con unas cheatsheets muy curradas.
  • Un mogollón de ejemplos con el código bien puesto.
  • Muchos controles
  • El respaldo de una gran empresa que soporta el proyecto (no te van a dejar tirado).
Cosas negativas que he visto y comprobado:
  • Puede llegar a ser bastante pesado para el cliente (las librerías javascript)
  • Es el framework más complejo con el que trabajar debido a que puedes hacer lo que quieras con él.
Este conjunto de librerías las puedes utilizar donde quieras porque son Javascript puro. De hecho, puedes mezclar diferentes librerías. ¿Os acordáis del ejemplo que puse en una de las entregas en el que se ponía el nombre y el servidor devolvía "Te devuelvo tu nombre: " y el nombre? Os acordéis o no, aquí tenéis ese mismo ejemplo pero implementado con YUI:

http://www.nidea-soluciones.com/PruebasAjax/YUI/yui1.html

El código javascript utilizado se divide en dos partes: primero tenemos que importar los scripts de YUI que vayamos a utilizar (lo miramos en su web para saberlo) y después realizamos nuestros propios scritps:







Los scripts a importar dependerán de qué es lo que vamos a utilizar de la librería de controles de Yahoo. En la página web se indica para cada caso cuáles son necesarios. La parte de programación es la siguiente:
















El meollo se encuentra en la línea YAHOO.util.Connect.AsyncRequest() que es la que crea el objeto XMLHttpRequest y realiza la llamada. Se le pasa el método, la url y una variable que contiene toda la información relativa a la función si va todo bien, la función si no va bien, los argumentos, etc. Es muy importante el orden, no podemos definir la variable callback antes de las funciones que manejarán las respuestas, ni podemos definir la variable callback después de la llamada al servidor.

Utilizamos también uno de los controles de YUI, el container en su versión panel. La programación con YUI se puede realizar de dos maneras distintas, por marcación o por Javascript. Todos los controles se pueden definir directamente en Javascript (caso del ejemplo) o definir en HTML (Markup). Al definir por HTML, cuando se llama al método render, la librería busca determinadas clases css y las convierte en controles. El mismo panel que se define en el ejemplo con HTML sería:











La librería lee las clases y las renderiza en pantalla en forma de panel.

Framework Dojo:
Este es el siguiente framework con el que trabajé. Tiene otras ventajas e inconvenientes que el YUI. Los que encontré fueron los siguientes:

Cosas buenas:
  • Un montón de controles
  • Definición en la programación más intuitiva que la de YUI.
  • Menos importaciones a nuestras páginas
Cosas malas:
  • La documentación es mucho peor.
  • Existen menos ejemplos en la utilización de los diferentes controles.
Veamos un ejemplo. Os he puesto el mismo ejemplo que con YUI pero programado con Dojo. Lo podéis ver en:

http://www.nidea-soluciones.com/PruebasAjax/Dojo/dojo1.html

El estilo de programación varía ligeramente entre ambos frameworks. En ambos disponemos de una parte de inicialización de dependencias que en el caso de YUI es mediante la incorporación de scripts y mediante Dojo se realiza más al estilo Java o C#:







Lo primero es importar la librería base dojo.js y después utilizamos la sentencia para importar aquellas partes que vayamos a utilizar. Podemos utilizar una sintaxis del tipo dojo.require() dojo.require("dojo.widget.*"); para importar todos los widgets. En este caso, como sólo vamos a utilizar el tipo Dialog pues lo importamos. La sentencia djConfig = {isDebug:true}; nos permite sacar mensajes de debug o de error en la librería por pantalla.

Dojo se diferencia de YUI en que al definir los elementos HTML, introducimos un nuevo parámetro llamado dojotype en el que le indicamos qué tipo de elemento dojo va a ser. De esta forma al inicializar el elemento en Javascript, la mayoría de la definición se encuentra en el elemento HTML. Vayamos por pasos: paso 1, el código HTML:
























En el código definimos tres divs a los que les decimos que son dojotype="dialog". De esta forma, Dojo sabe que tiene que renderizarlos como diálogos. Además les definimos una serie de características propias de Dojo (las subrayadas en rojo): bgcolor(color de fondo de la pantalla no del div), bgOpacity(opacidad del fondo de la pantalla), toogle (forma en la que aparece o desaparece la pantalla) y toogleDuration (duración del efecto de aparecer y desaparecer).

El resto del código es html normal. Veamos cómo se definen los diálogos y las funciones (ved que llamo a dos funciones Javascript CargarNombre() y Empezar()).
























He dividido el Javascript en trozos. En la primera parte tenemos las definiciones de las variables que vamos a utilizar después, los tres diálogos, y las dos funciones manejadoras de los eventos de respuesta correcta y respuesta incorrecta, hasta aquí todo igual que antes. Tenemos también la función init, que se ejecuta al cargar la página que define el primer diálogo que aparece en pantalla. La definición es muy simple, solamente utilizamos la sentencia dojo.widget.byId() y le pasamos el id del div que va a ser el diálogo (ese div tiene que tener el dojotype="dialog"). Le definimos el botón que va a ocultar el diálogo con la sentencia setCloseControl(). Ved que podemos utilizar con los diálogos las sentencias show() y hide() para mostrarlos u ocultarlos desde cualquier parte del código. ¿Y las llamadas a servidor cómo se hacen? Pues veamos el resto del código:
















Tenemos la función CargarNombre() que muestra el diálogo de espera y llama al servidor. Con Dojo, las llamadas se realizan utilizando el método dojo.io.bind al que le pasamos parámetros. Los más comunes y necesarios (algunos) son: url (dirección a la que llamar), load (método que controlará la respuesta correcta del servidor), error (método que manejará la respuesta de error del servidor), mimetype (mimetype de los datos de la llamada).

Dojo también permite realizar llamadas cross-domain mediante el método bind(), pero hay que importar el espacio dojo.require("dojo.io.XhrIframeProxy"), proque la llamada se realiza mediante un iFrame Proxy. Esto está aún en pruebas así que os aconsejo que vayáis a la documentación y os lo leáis.


Conclusión (hasta la próxima):
Como se me está haciendo demasiado largo el post, dejaremos los dos frameworks restantes para el siguiente. Sólo comentaros mi experiencia con ambos: personalmente prefiero el framework de Dojo que es bastante más intuitivo de utilizar, aunque YUI tenga más documentación (es realmente buena), cuando empiezas a trabajar con Dojo y te empiezas a enterar de cómo funciona, es más liviano. De todas formas, al ser frameworks completamente independientes de plataformas, siempre podéis conjugarlos y utilizar aquellas partes que más os gusten de uno y de otro.

Proximamente: GWT y ASP.NET AJAX

martes, julio 03, 2007

AJAX PARA SUPERCAMPEONES o ¿Sabremos alguna vez qué es AJAX? (III)

Hala, de vuelta con el tema Ajax (la verdad es que da mucho juego el tema...). En esta tercera entrega de esta serie nos vamos a centrar en los siguientes dos temas:
  • Llamadas simultáneas: es decir, realizar múltiples llamadas a diferentes sitios a la vez.
  • Llamadas asíncronas secuenciales: este es un tema importante, saber cómo hacer llamadas asíncronas de forma ordenada.
Si no os habéis leído los posts anteriores, os recomiendo que lo hagáis:
Como sé que ya te los has leído, Nacho, puedes seguir con el siguiente punto ;P. En este post, terminamos la serie de AJAX PARA CAMPEONES o AJAX A PELO o AJAX KAMIKAZE, es decir, ajax para frikies.

Llamadas simultáneas
Una de los beneficios más importantes de trabajar con hebras de ejecución es que podemos crear tantas como nos permita el entorno (hardware, línea de comunicación, etc.) y el objeto XMLHttpRequest no es menos. Trabajando con AJAX podremos, por lo tanto, lanzar mútliples hilos de comunicación de forma simultánea que ejecutarán tareas distintas. Tendremos que tener cuidado de manejar correctamente las respuestas, de forma que sepamos siempre de quién es cada una.

En el ejemplo que os pongo aquí, podéis realizar tres llamadas simultáneas para que se carguen en los divs inferiores la página web que hayáis puesto. No es que esté demasiado currado pero menos es nada.

Ejemplo: http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax5.html

Existen ciertas peculiaridades para que este ejemplo funcione:
  • Se ha creado una nueva función EnviarPeticionConParametro que además de realizar la petición le pasa un parámetro a la función que maneja la respuesta (aparte del objeto XMLHttpRequest).
  • Se ha implementado un Proxy al que llama la página para que se puedan hacer llamadas asíncronas CROSS-DOMAIN. Ésto lo explicaré otro día.
El código de la nueva función es el siguiente:










Como veis, introducimos un nuevo argumento llamado "parametro" que se le pasará a la función callback. Con este parámetro podremos decirle a la función callback qué objeto es el que ha realizado la llamada y ha respondido. Lo marco porque es muy importante ya que cada llamada tardará el tiempo que sea y devolverá el resultado en orden aleatorio. Tenemos que disponer de algún método que asocie la llamada con la respuesta.

Para entenderlo mejor, veamos el código de la página y cómo se realiza la llamada:



















En este caso, tenemos la función CargaURL(posicion), donde en posición se le pasa un 1, un 2 o un 3, dependiendo de qué botón es el pulsado. En base a ese número, se leerá el input correspondiente y se mostrará el panel de espera asociado. Finalmente se llama a la función EnviaPeticionConParametro y se le pasa la posición como parámetro final.

A la función que maneja la respuesta le llega el parámetro de la posición por lo que es capaz de poner la respuesta en el div correcto y oculta el div de espera correspondiente. De esta forma podemos tener una sola función que gestiona todas las llamadas y otra función que gestiona todas las respuestas. Si no lo hiciésemos así tendríamos que asociarle una función diferente a cada respuesta.

Os pongo un dibujo que como sabéis me molan y en el post anterior no tuve oportunidad de poner ninguno:











Las peticiones se envían al servidor, el cual las gestionará y tardará un tiempo x. Al ser asíncronas, las peticiones se evaluarán de forma simultánea y a medida que las vaya resolviendo irá mandando la respuesta. El orden de evaluación y respuesta no es fijo por lo que el orden de llegada de las peticiones no tiene por qué tener relación con el de salida. Es muy típico equivocarse con este concepto y escribir lo siguiente:

function MiFuncionQueRealizaMuchasCosas(){
// Primera accion asíncrona
ActualizaDatos();
MuestraDatosActualizados();
}

Error, al ser la función ActualizaDatos una llamada asíncrona a servidor, perderemos ese hilo de ejecución hasta que lo recoja el manejador de la respuesta. Por esto, la función MuestraDatosActualizados() no mostrará esos datos.

Llamadas asíncronas secuenciales
Por fin, el último ejemplo, lo último del AJAX PARA CAMPEONES. Este ejemplo se lo dedico con mucho cariño a Nacho porque sé que es tela de friki del Linux y en especial de Kubuntu y Ubuntu. Espero que te guste.

Como ya estaba harto de páginas html guarras con el texto a pelote decidí currarme un poquillo más este último ejemplo del post. En este ejemplo se realizan seis llamadas a servidor secuenciales, hasta que no se recibe la contestación de una no se realiza la siguiente. Podéis ver el ejemplo en la siguiente dirección (funciona mejor con Firefox porque el IE, a partir de la segunda vez, se pasa por el forro el delay que le tengo puesto en servidor):

http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax6.html

Mola cantidad, eh? Por lo menos le damos un poco de aqué al tema. En fin, vamos al lío. ¿Cómo se hace esto? Aparte del tema gráfico (cada uno lo pone como más le gusta), la secuenciación de llamadas se realiza de la siguiente manera (os lo pongo en tres imágenes porque no me cabía en una):


















































Lo que hacemos es lo siguiente:
  1. Cuando el usuario pulsa sobre el botón, mostramos el divProgreso y le ponemos la primera imagen grande y su texto. Llamamos a la url Codigos/PruebaAjax6.aspx para ir a servidor.
  2. Cuando se recibe la respuesta, se pone la imagen en pequeño, se pone en grande la siguiente y la descripción de la acción y se realiza la llamada a la página con el parámetro del siguiente paso.
  3. Así sucesivamente hasta que en la última llamada, invocamos a la página redireccion.html. Obtenemos su código html y lo metemos dentro del div wrapper que engloba a toda la página.
Viéndolo en un dibujillo:















Es en las funciones callback donde realizamos la siguiente llamada.

El finaaaal deeeel veraaanooooo, llegoooo.....
Como todo, en algún momento hemos de llegar al final e igual que el verano todo acaba. Creo que con esta serie de ejemplos cubrimos la base de la comunicación asíncrona y del AJAX PARA CAMPEONES. Como os habréis percatado, el manejo del Javascript es fundamental (por Dios, nooooo), aunque, como veremos en posts posteriores, existen frameworks que nos ayudarán en nuestro cometido (un poco). Es importante que os deis cuenta que es indiferente el lenguaje de programación que utilicéis (yo lo he hecho todo en html plano), simplemente debe permitir hacer llamadas a funciones Javascript.

En próximos capítulos:
  • Frameworks Ajax
  • Llamadas Cross-Domain
Se me está ocurriendo hacer también algún post con el tema de los Mash-Ups.

lunes, julio 02, 2007

AJAX para CAMPEONES o ¿Qué es eso del AJAX? (Segunda Parte)

Como su nombre indica, en este post continuo con el anterior de ¿Qué es eso del AJAX?. Si no lo habéis leido, leedlo para cogerle el hilo a este. En este post vamos a tratar el tema del que denominé como AJAX PARA CAMPEONES, es decir, la programación a pelo, vía Javascript, de las llamadas asíncronas y de toda nuestra lógica del lado de cliente. Empecemos pues.

Lo primero: las herramientas
Si empezasteis a trastear un poco con el ejemplo del post anterior, os daríais cuenta que la programación con Javascript es muy puñetera, cualquier mínimo fallo en una letra y nada funciona y a ver quién es el guapo que sabe dónde está el fallo. Javascript adolece de falta de herramientas para trabajar con él y nos podemos tirar horas delante de un código sin saber que leñe falla y sin la menor ayuda. Sin embargo (aquí vengo en plan salvador de los programadores) existen varias herramientas que nos pueden ayudar en nuestra ardua tarea:

  • Firebug: extraordinario complemento de Firefox que nos permite inspeccionar todo el HTML, el Javascript, el DOM, las hojas de estilo. Podemos depurar el código Javascript, ponerle puntos de interrupción, etc. Una herramienta indispensable para los campeones del AJAX.
  • Aptana IDE: un entorno de desarrollo, aunque también existe como plugin de Eclipse para el desarrollo de Javascript. Es magnífico y tiene un puñado de funcionalidades buenísimas: autocompletado, ayuda dinámica, nos dice la compatibilidad de exploradores para cada método, depuración, etc. También incluye las librerías YUI, Dojo, Mochikit, Rico y AFLAX listas para trabajar con ellas (de esto hablaremos en un post posterior).
Por supuesto, antes de empezar, tened dispuesto Internet para consultar las múltiples dudas que os vayan saliendo.

En fin, no queda más remedio, vamos al lío
En el post anterior vimos un pequeño ejemplo de una llamada básica a servidor para obtener un fichero de texto. En ese caso, lo único que hacíamos era llamar al servidor y poner el texto en un div. Vamos a extender un poco este concepto con otro ejemplo. En este caso ponemos una caja de texto donde el usuario introduce el nombre, pulsa el botón y se realiza una llamada a servidor que devuelve "Te devuelvo tu nombre:" seguido del nombre. Este ejemplo tiene tres particularidades:
  1. Cuando el usuario pulsa el botón aparece un cartel de espera, indicando al usuario que se está cargando la página
  2. He introducido un delay en servidor de 2 segundos para que se aprecie el cartel de espera.
  3. Se han mejorado las funciones de creación del objeto XMLHttpRequest y la de envio de la petición (ahora veremos en qué).
El ejemplo lo podéis ver aquí:
http://www.nidea-soluciones.com/PruebasAJAX/PruebaAjax2.html

En este caso he llevado las funciones generales (la de creación del objeto y envío de la petición) a un fichero javascript independiente llamado FuncionesAJAX.js. Veamos en primer lugar este fichero y cómo han cambiado las funciones:

























La función ObjetoAjax() la hemos cambiado en el sentido de que ahora contempla todas las posibles inicializaciones que existen. La función EnviarPetición acepta ahora 5 argumentos:
  • objetoAjax: será el objeto que inicialicemos con la función anterior. Se inicializa fuera de esta función para que podamos lanzar múltiples comunicaciones a la vez a través de objetos distintos.
  • método: tendremos que poner si queremos hacer un "GET" o un "POST".
  • url: dirección del servicio web o página o recurso con el que queremos comunicarnos.
  • async: true si queremos que la llamada sea asíncrona o false en el caso que no. Si es asíncrona tendremos que definir un método que maneje la vuelta.
  • callback: nombre del método que manejará la vuelta. La función EnviarPetición se encargará de enganchar la petición con este manejador y pasarle como parámetro el objeto XMLHttpRequest utilizado.
Como veis, esta función es mucho más general que la anterior y con ella podremos hacer mejor las cosas.

Veamos ahora el código de la página PruebaAjax2.html, la primera parte, dentro de la etiqueta HEAD es:
















En esta parte incluimos el script FuncionesAJAX.js y seguidamente definimos dos funciones:
  • CargaURL(): esta función es la que inicializa el objeto Ajax, pone visible el panel de espera y llama al método EnviarPeticion. Como veis, llamamos a una página .aspx pasándole como parámetro el nombre. La página devuelve un flujo con el texto. Esta llamada se podría realizar a cualquier página o servicio web que hubiésemos programado nosotros en cualquier lenguaje. Cuidado con intentar llamar directamente a páginas de otro dominio diferente de donde tengáis las páginas u os saltará un error al abrir la conexión. Esto se llama LLAMADAS CROSS-DOMAIN, y no se pueden hacer directamente, hay que utilizar un proxy o elementos intermedios.
  • FinCargaURL(objeto): es la función que maneja la respuesta del servidor. Cuando nos responde el servidor, esconderemos el panel de espera y pondremos el texto en el div correspondiente. Ved cómo se pasa como argumento el objeto Ajax encargado de la comunicación.

La parte del BODY de la página es:















En esta parte definimos únicamente la disposición de los elementos. Tenemos el div pnlEspera que contiene la etiqueta de espera, al que le ponemos en el estilo display:none para que inicialmente no se vea. Este ejemplo está bien porque, por lo menos, le ponemos un cartel al usuario diciéndole que algo estamos haciendo (sin demasiada información, pero bueno). Por supuesto esto es muy mejorable y remarco los siguientes aspectos:
  • El usuario puede volver a pulsar sobre el botón mientras se está haciendo la llamada. En determinadas circunstancias esto no debe poderse hacer. Imaginad una operación crítica que se realiza varias veces porque el usuario le ha dado al botón sin parar.
  • La información proporcionada en el cartel no es demasiado explícita. Habrá determinados momentos en los que se realicen operaciones largas, de varios pasos, y haya que informar al usuario de por donde va el tema.
Por esto, pasamos al siguiente ejemplo.

Por Dios, más no, por favor
Pues si, un poco más de Javascript a pelo. En este ejemplo (el tercero del total si no me falla la cuenta), deshabilitamos el botón que realiza la llamada mientras estamos en ello. Podéis ver el ejemplo en la siguiente url:

http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax3.html

Mola, verdad? Lo único que hacemos es deshabilitar el botón en la función CargaURL y habilitarlo en la función FinCargaURL. Veamos el código:




















Le ponemos la propiedad "disabled" a true y luego la volvemos a cambiar a false. Ya empezamos a darle un poquillo de forma al tema, cuidando un poco los detalles, aunque, pequeños saltamontes, el camino aún no ha terminado y es largo y duro.

En el siguiente ejemplo, le hemos incluido un contador de tiempo, que se inicia de forma que el usuario sabe cuánto tiempo tarda en volver la información. Lo podéis ver en:

http://www.nidea-soluciones.com/PruebasAjax/PruebaAjax4.html

Aunque no tiene mucha utilidad si que sirve para ilustrar que podemos mostrar información en pantalla mientras se realiza la llamada, de verdad es asíncrona. En este caso hemos puesto un contador, pero podría ser cualquier tipo de información. En un ejemplo posterior veremos cómo ir diciéndole al usuario en qué estado se encuentra la operación (para poder darle más información). El código Javascript de esta página se complica un poco más:
























Jugamos en este caso con la función setInterval de Javascript que ejecuta cada x milisegundos la función que le pasemos como argumento. La función clearInterval para este ciclo.

Final, por ahora...
Como, otra vez, se me está haciendo demasiado largo el post, finalizo aquí. En posteriores post trataremos los siguientes casos:
  • Múltiples llamadas a la vez
  • Información del estado al usuario
  • Llamadas Cross-Domain
  • Utilización de Frameworks que nos ayuden en nuestro camino con AJAX.


miércoles, junio 27, 2007

¿Qué es eso del AJAX?

Algunos pensarán que el AJAX es un equipo de fútbol holandés, otros pensarán que les da igual qué es lo que es, otros pensarán que tiene algo que ver con internet (nos vamos acercando al tema). En este post voy a intentar dar una primera idea que, si puedo iré extendiendo en sucesivos posts, de qué es realmente AJAX y qué podemos hacer con él.

La definición es:

AJAX: Asynchronous Javascript and XML

muy bien, y esto ¿qué significa?

Empezaré contando mi pequeña historia con AJAX, mi experiencia con AJAX comenzó cuando un conocido me comentó que estaban haciendo un sistema web con ATLAS. Yo pensé "¿para qué meter un atlas en un sistema web?", luego me enteré que ATLAS es una implementación de ASP.NET para AJAX. A estas alturas aún no sabía qué era AJAX. Con el tiempo empecé a investigar por mi cuenta y a jugar con diferentes lenguajes de programación y frameworks javascript: programé con PHP, utilicé el GWT (Google Web Toolkit) para Java, enredé con el framework Dojo y Rico, programé con ASP.NET, etc. En fin que me mareé viendo herramientas y programando con ellas, pero, realmente ¿QUÉ ES AJAX?

Mi último proyecto, con el que estoy ahora mismo (aprovecho para comentarlo) es un portal libre para compartir cursos de formación (http://learning.nidea-soluciones.com) es donde más he trabajado con AJAX y todas las técnicas relacionadas, así que, vamos al lío de verdad.


¿Qué es AJAX?

AJAX no es ni más ni menos que un mecanismo que nos permite realizar llamadas asíncronas al servidor desde un página web. Así suena muy poca cosa, pero en realidad abre todo un mundo de posibilidades (y problemas...).

¿Cómo eran las cosas antes de AJAX? Antes de AJAX, una página web se componía de etiquetas HTML y de etiquetas de servidor (utilizadas por el lenguaje de programación). Cada vez que un usuario realizaba cualquier acción en una página web que requiriese de la actualización de su contenido, se ponía la pantalla en blanco (mientras se realizaba la comunicación con el servidor) y luego volvía a aparecer con la actualización puesta. ¿Por qué pasaba esto? porque lo que los navegadores entienden es el HTML, y las etiquetas de servidor las debe sustituir el servidor por HTML con los datos correctos. Veamos el siguiente ejemplo:

Tenemos una página simple programada en ASP.NET (es lo que tengo más manío):











Lo único que hace esta página es pedir un nombre y al pulsar sobre el botón, pone el nombre que se ha escrito en una etiqueta. Sin embargo, éste lenguaje no es entendido por el navegador, por lo que el servidor web, lo que hace es sustituir las etiquetas por lo que corresponda en HTML. La primera vez que se ve la página, el código enviado es:














Todas las etiquetas han sido sustituidas por sus correspondientes etiquetas HTML. Si el usuario introduce un nombre y pulsa sobre el botón "btnBoton" que pone Púlsame, la página se tendrá que recargar para que aparezca el nombre en la etiqueta "lblNombre". El servidor (porque se le indica así en el fichero de código que acompaña a esta página) devolverá la siguiente página:














La página devuelta tiene en la caja de texto el nombre "Manolo" y en el span también. Al pulsar el botón, hemos tenido que ir al servidor para que recompusiese el HTML y lo enviase de vuelta al navegador. El tiempo que tarde en llegar la petición al servidor, en que éste evalúe las acciones, obtenga los resultados, rehaga el HTML y llegue de vuelta al navegador, será el tiempo que esté nuestro explorador en blanco. Esto es así porque las operaciones son SÍNCRONAS (lo remarco porque este es el quid de la cuestión).

Lo que nos permite AJAX es lanzar una llamada asíncrona al servidor para que nos envíe la información que requiramos de vuelta, sin que el usuario pierda el control de la interfaz de usuario. Como me gustan mucho los dibujos, veámoslo en uno de ellos:




















En el primer caso, se realiza una llamada a http://www.nidea-soluciones.com (os la marco por si queréis visitarla). El servidor web devuelve el HTML de la página, el explorador lo lee y lo pinta en la pantalla. Si el usuario pulsa algún botón o realiza alguna acción que requiera una respuesta del servidor (actualización de una parte de la página), se enviará una petición de actualización al servidor y perderemos el control en el explorador, la página se quedará en blanco esperando que el servidor recomponga todo el HTML y se lo envíe de vuelta. Este tiempo variará dependiendo del servidor, de las líneas de comunicación y de lo que queramos actualizar. En ocasiones puede llegar a ser muy frustrante puesto que no sabemos si se ha colgado el sistema, si la línea se ha caído, por dónde va el proceso, etc. y actualizamos la página para volver a darle o nos salimos del sitio.

En el segundo caso utilizamos AJAX en nuestra página web y el proceso varía ligeramente. La primera llamada al servidor nos devuelve la página web, igual que el ejemplo anterior. Sin embargo, a partir de ese momento, todas las peticiones de actualización de partes de la página se realizan con llamadas asíncronas a servidor. Esto lo que hace es lanzar una hebra de ejecución diferente de la que tiene el control de la página y, esta hebra, contacta con el servidor y le pide la información. En Javascript, habremos implementado un manejador para el evento de recepción de la respuesta. Cuando llegue la respuesta se ejecutará el código de ese manejador, donde le diremos qué tiene que hacer con los datos que nos envía el servidor. Durante el tiempo de ida y venida al servidor, la hebra principal mantiene el control de la página, posibilitando que el usuario siga haciendo cosas con ella. Podría realizar más peticiones a servidor y se lanzarían nuevas hebras.

Hasta aquí muy bien pero, ¿y eso cómo leñe se hace?

La primera alternativa para trabajar con AJAX es la que denomino, AJAX PARA CAMPEONES. La pongo en mayúsculas y coloreado porque esta opción es la de trabajar a pelo con Javascript y con el objeto XmlHttpRequest (que veremos ahora). Esta alternativa es un poco sádica pero creo que es necesario que sepáis realmente cómo funciona. Una vez superado este nivel podremos trabajar con la opción AJAX COMODO, en la que utilizaremos algún framework de los existentes.

Vamos a ver un ejemplo práctico (aquí iba a poner un ejemplo pero Blogger me bloquea las llamadas asíncronas), por lo que podéis ver el ejemplo en:
http://www.nidea-soluciones.com/PruebasAJAX/PruebaAJAX1.html.

En este ejemplo, al pinchar en el enlace lo que se hace es inicializar el objeto xmlHttpRequest (encargado de realizar la llamada asíncrona) y hacer un GET asíncrono a http://www.nidea-soluciones.com/PruebasAJAX/prueba.txt El texto de respuesta lo coloca en una etiqueta que está justo debajo del enlace. Veamos el código:






















Si nos fijamos en la parte BODY, tenemos un hipervínculo que al pulsarlo lanza la función CargaTexto(), hecha en Javascript, y tenemos un SPAN llamado textoAjax. Vamos a ver las tres funciones Javascript que hemos definido:

Función ObjetoAjax(): función encargada de inicializar el objeto XMLHttpRequest para poder realizar llamadas asíncronas a servidor. Esta función comprueba el tipo de explorador porque Firefox e Internet Explorer utilizan diferentes inicializaciones para este objeto (como siempre...).

Función CargaTexto(): esta es la función que se invoca cuando el usuario hace clic sobre el enlace. Esta función realiza tres cosas distintas:

  1. Utiliza el objeto Ajax para abrir una conexión GET con la URL http://www.nidea-soluciones.com/PruebasAJAX/prueba.txt.
  2. Declara cuál va a ser la función que se ejecute cuando llegue la respuesta a la llamada al servidor. En este caso, dicha función va a ser capturaPeticion.
  3. Lanza la llamada.

Función CapturaPeticion(): cuando se recibe la respuesta se lanza esta función que lo que hace es poner el texto de la respuesta en la etiqueta SPAN definida.

Este ejemplo es muy básico pero ilustra bastante bien el ciclo de llamada y respuesta de AJAX. Siempre tendremos estas tres funciones: una que inicializa el objeto, una que realiza la llamada y otra que recibe la respuesta. En sucesivos posts iremos viendo cómo podemos mejorar este ejemplo (ya está siendo muy largo este), como por ejemplo:
  • Etiquetas de espera para que el usuario sepa que algo se está haciendo.
  • Control de la concurrencia en servidor.
  • Deshabilitar controles a la hora de ir a servidor.
  • Informe del estado de la operación
  • ...
Estas son cosas importantes que hay que tener en cuenta a la hora de programar con AJAX, porque al introducir el elemento asíncrono, se incrementa la complejidad en nuestros desarrollos.


Finalmente, ¿qué NO es AJAX?

También es importante saber qué no es AJAX. AJAX es, simplemente, la posibilidad de realizar llamadas asíncronas a servidor. De ésto se pueden derivar muchas herramientas y controles, los llamados rich-controls, que utilizan AJAX. Podremos implementar grids que carguen los datos dinámicamente utilizando el objeto XMLHttpRequest y funciones Javascript, ventanas modales que carguen información, etc. Todos estos controles utilizan AJAX y CSS para ayudarnos en nuestros desarrollos, pero AJAX sólamente es el objeto XMLHttpRequest.




viernes, junio 22, 2007

¿Otro post no? XML for Mayor!

Como veo que la cosa está más muerta que un cordero la noche después del fin del Ramadán digo...¿voy a escribir no? ... pero ... ¿qué coño escribo?

Pues como últimamente he estao aprendiendo cosillas sobre XML, RDF, RDFa, JDOM, DOM, SAX, XML-RPC, SOAP, XSLT, SNMP, J2EE, J2ME, BGP, IPv6, y demás parafernalias (cómo mola escribir siglas, no importa que no tengas puta idea, quedas como un señor poniéndolas ;) ), pos me he decidío a contaros un poquillo de estas tecnologías en diferentes post por entregas. Si os aburro no tenéis más que decirlo.

Y pa empezar, vamos a introducirnos levemente en el maravilloso mundillo del XML.

Actualización(23/06/07):
Como los feeds (orígenes, RSS, como los queráis llamar) se envían mediante XML, paradojas de la vida, quien lea este post recibiéndolo desde un agregador probablemente no lo lea bien porque interpretará el código XML y el resultado será que no se le mostrarán las etiquetas, sólo su contenido. Por ello, por el momento y a estas alturas de la noche no se me ocurre más que entrar vía web para leerlo sin problemas. Mil perdones. ¿A alguien se le ocurre una solución?



XML

Mi descubrimiento de XML como metalenguaje para "casi todo" ha sido como encontrarse con un hermano perdido. Uno se pregunta...¿cómo coño no lo vi antes? ¿he estao tirando to este tiempo a la basura?

¿De ande ha salío ésto?

XML surge más o menos como una simplificación de SGML, que viene a ser un lenguaje un tanto más ambíguo pero mucho más extenso y rico. SGML se lo inventaron por allá por los "unites estates" cuando un grupo de editoriales decidieron que los autores tenían que definir el contenido de forma lógica mientras los editores se dedicaran a la presentación física que es pa lo que al fin y al cabo les pagan :). Así después de unos cuantos quebraderos de cabeza se llega a un estándar ISO con una especificación muuuuy compleja. Pero claro, esto pa los libros y un grupo reducido de gente dispuesta a andarse con rodeos está mu bien, pero pa Internet digamos que la cosa estaba chunga. Así surge una simplificación que aprovechaba la experiencia previa de SGML para orientarlo a Internet y que permitía fácilmente la definición de nuevos lenguajes (de ahí el eXtensible de "eXtensible Markup Language"). Sobre todo, lo que se buscaba era un lenguaje que fuese fácil de procesar, y a la vista está que lo consiguieron. Podíamos decir que con XML se consiguió un 80% de la funcionalidad de SGML con sólo un 20% de su complejidad. Todo un logro, ¿verdad?

Pa no confundirnos, y como a alguno ésto le puede sonar a HTML aclaremos que
XML == SGML--
pero...
XML != HTML++

Aunque la sintaxis XML pueda recordarnos a HTML (de hecho las versiones actuales de HTML son ya XML, más concretamente se le llama XHTML), XML presenta algunas diferencias con el tradicional HTML de to la vida. Algunos ejemplos son:
  • En HTML podíamos alegremente cerrar y abrir las etiquetas donde nos diese la gana, e incluso algunas ni cerrarlas, por lo que se suponía </p> por defecto. En XML ni de coña. Cada etiqueta que se abra debe ser cerrada adecuadamente, e importando y mucho el orden. Así mientras en HTML podíamos escribir <p><i>jeje</i></p>, en XML no se puede en aras de un procesamiento más simple y de más claridad.
  • Mientras en HTML los valores de los atributos podían o no ir entre "", en XML es estrictamente obligatorio que lo hagamos.
  • En HTML podíamos dejar un atributo vacío sin cerrar, pero en XML todo elemento se cierra. Por ejemplo:
    (HTML) <img src="http://www.blogger.com/...">
    (XML) <img src="http://www.blogger.com/..." /> (nótese que pa ahorrarse el curro de volver a poner la etiqueta con "/" delante, si el elemento es vacío se puede poner el símbolo "/" antes de cerrarlo).
Dicho ésto vamos a ver un ejemplo sencillico XML y sobre él ya vamos trabajando.

Veamos qué pinta tiene

<?xml version="1.0" encoding="UTF-8">
<!DOCTYPE empresa SYSTEM "empresa.dtd">

<!-- Definición de una empresa emprendedora, "así tó wapa" podíamos definirla-->
<empresa clase="wenaquetecagas" contacto="nidea@nidea-soluciones.com">
<nombre>N-IDEA. Nuevas Ideas</nombre>
<url tipo="web">http://www.nidea-soluciones.com</url>
<url tipo="blog">http://nidea-soluciones.blogspot.com</url>
<direccionpostal>C/ Tejuela, 25. Alcalá la Real (Jaén). CP: 23680</direccionpostal>
</empresa>


Como véis, es bastante intuitivo. Yo defino lo que quiero y con la lógica que yo quiero imprimiéndole semántica a lo que escribo. De hecho sin saber programar una persona que leyera el código de arriba muy probablemente comprendería el mensaje. Ésa es la idea.

Pero vamos a lo que nos ocupa. Bueno, aquí tenemos varias cosas. Primero tenemos
<?xml version="1.0" encoding="UTF-8">
Ésta es lo que se llama una "processing instruction", pero además es una especial. Es la que debe contener todo documento XML al principio. Ántes de ella no se puede escribir nada, ni siquiera comentarios, para que el documento sea válido. Las processing instruction sirven para pasarle información a la aplicación que usa el documento XML. Normalmente su sintaxis es:
<?Programa Instrucciones?>
Como por ej: <?JAVA_OBJECT JAR_FILE="/nidea/mijar.jar"?>
Por supuesto, para no confundir al bicho, está prohibido empezar la processing instruction con "xml" ya que este nombre está reservado para el principio del documento como habéis visto.
Lo que sigue a "xml" son dos atributos de nombre version y encoding, y de valores 1.0 y UTF-8 respectivamente. Aunque os lo podéis imaginar, son la versión y la codificación del documento. La version es obligatoria que sea 1.0 (creo), y que aparezca siempre, pero la codificación puede no aparecer o puede ser distinta. Por ejemplo, un tipo de codificación muy típica es la ISO-8859-1 que viene a ser la que define los caracteres españoles específicamente. La UTF-8 es también llamada Unicode-8 y es la que he usao en este caso.

Siguiente cosa rara que vemos es...
<!DOCTYPE empresa SYSTEM "empresa.dtd">

Es una etiqueta especial ya que como se puede observar no sigue la sintaxis de xml para las etiquetas. No va cerrada, el nombre de la etiqueta comienza por ! en lugar de por letra o "_" y tiene espacios. Entonces...¿qué #!*+ es? Pues se trata de la definición del tipo de documento. Como ésto es sólo una breve introducción no entraré en detalles, pero es necesario saber que debe apuntar al elemento raiz del documento xml (lo que sigue a !DOCTYPE, en nuestro caso empresa) y al DTD del documento, que viene a ser un fichero que especifica la estructura de nuestro documento xml, qué elementos pueden ir dentro de otros, qué tipo de datos se acepta en cada elemento, cuántas veces puede aparecer un elemento, etc. Pero eso ya lo veremos luego. En nuestro caso, el DTD está en la misma carpeta del documento xml y se llama "empresa.dtd".

Después vemos un comentario. Es eso de...
<!-- Definición de una empresa emprendedora, "así tó wapa" podíamos definirla-->
Pos eso, se trata de un comentario. Algo que el/la programador/a escribe para que no sea interpretado por los programas que hagan uso del documento, pero que puede servir para hacer más legible el mismo o para explicar algunos detalles específicos a otros/as programadores/as que puedan leer nuestro xml. En ocasiones también se usa para ocultar elementos a los programas. En fin, usarlos mola, pero no usarlos no hace tu documento no válido.

Y luego viene el documento en sí, con sus etiquetas, sus atributos y demás. De eso creo que poco hay que explicar. La cosa está en imaginar de forma lógica la información que queremos representar y luego escribirla con coherencia. Si queremos representar en un documento una empresa que puede ser de varias clases y que tendrá un único e-mail de contacto, una forma de representarlo sería con la que escogí arriba:
<empresa clase="wenaquetecagas" contacto="nidea@nidea-soluciones.com"></empresa>
pero ahí ya está vuestra imaginación y el tipo de datos que queráis representar. Si además sabemos que una empresa tiene un nombre, nos podemos inventar un nuevo elemento que esté dentro de "empresa" y cuya etiqueta sea "nombre". Si sabemos que la empresa tendrá urls de varios tipos y múltiples, una fórmula puede ser crear otros tantos elementos también dentro de "empresa" de etiqueta "url" y con un atributo "tipo" que defina el tipo de url que es (página web, blog, wiki...). Si por último sabemos que las empresas representadas por este tipo de documento pueden tener una dirección postal que queramos representar, nos podemos imaginar un último elemento "direccionPostal" que almacene esta información. Pero lo que os dije antes, todo es imaginar e inventar. Ahí los creadores sois vosotros/as.

Bueno, visto un ejemplo práctico sobre el que habremos visto la dinámica de XML, vamos a ver algunas cuestiones específicas de los elementos y los atributos.

Elementos y Atributos

Los elementos deben comenzar su nombre por letra o underscore (_) seguido de alguna combinación de letra, underscore, números, puntos, dos puntos o guiones. No puede contener espacios en blanco y no puede comenzar por "xml" en ninguna de sus variantes (xml, xmL, xMl, xML, Xml, XmL, XMl o XML). En principio no existe longitud máxima para el nombre aunque hay que tener cuidado con algunos parsers de nivel superior que puedan tenerlo.

Los atributos se definen en la etiqueta de comienzo de un elemento. Definen pares nombre="valor". No pueden estar duplicados dentro de la misma etiqueta, usan para su nombre las mismas reglas que los elementos y son obligatorias las comillas para determinar el valor. Como es lógico, el símbolo de las comillas (") no puede aparecer en el valor del atributo, para lo cual se utilizará la entidad predefinida & quot; (sin el espacio entre & y quot;. No lo junto porque entonces vuestro navegador os lo mostraría como " y entonces habríamos hecho un pan con unas hostias).


DTD

Veamos lo último que nos falta para poder definirnos nuestro lenguaje XML a nuestro gusto. Pongamos que vamos a definir un nuevo lenguaje que llamaremos NideaML.
Como hemos visto antes, NideaML es un lenguaje sencillico y que sirve para definir una empresa dado su nombre, clase, correo-e de contacto, urls de varios tipos y dirección postal. Si dejáramos nuestro documento anterior tal cual eliminando la sentencia de !DOCTYPE, ya no sería NideaML, sería XML normalico y corriente porque no existirían restricciones que impidieran a nadie meter otros atributos en el documento o inventarse nuevos elementos, o no colocarlos en su debido orden. Si no hay DTD, se asume que cualquier cosa puede ir dentro de cualquier cosa y se admite cualquier tipo de elemento. ¿Pero cómo podemos añadir estas restricciones? Como ya os dije antes, para eso está aquí nuestro amigo el DTD.

Como antes, no hay mejor forma de aprender algo en cualquier tipo de programación que viendo algo programado, así que os mostraré cómo quedaría el DTD llamado empresa.dtd, que quedaría como sigue...

<!ELEMENT empresa (nombre, url*, direccionPostal?)>
<!ATTLIST empresa
clase CDATA #REQUIRED
contacto CDATA #REQUIRED>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT url (#PCDATA)>
<!ATTLIST url
tipo (web | blog | wiki | proyecto) "web">
<!ELEMENT direccionPostal (#PCDATA)>

¿Qué? ¿Cómo lo veis? ¿Bonito no? :).
Se puede intuir más o menos la sitaxis, pero vayamos poco a poco. De lo primero que ya os habréis percatao es que no se trata de XML, se parece más a nuestro querido !DOCTYPE que al resto de lo que hemos visto.

Bien, queremos definir qué elementos se permiten, cuáles están dentro de cuáles, qué atributos tienen, si son o no obligatorios y de qué tipo son.

Empecemos por los elementos. Los elementos se declaran con !ELEMENT seguido de su nombre y entre paréntesis el tipo de datos que van a contener indicando cuántas veces van a ocurrir. El nombre del elemento sigue las reglas que ya citamos antes, y el tipo de datos que van a contener pueden ser otros elementos (se pone el nombre de éstos), texto normal (#PCDATA), una combinación con expresiones regulares de las anteriores (ej: nombre | #PCDATA | (otroNombre, otroMas) ), cualquier cosa (ANY) o nada (EMPTY).
El número de ocurrencias de cada cosa que puede entrar en nuestro elemento lo definen unos caracteres que se añaden al final del nombre del elemento/expresión regular. Veamos nuestros símbolos para las expresiones regulares:
si no ponemos nada implica que ocurre sólo una vez
+ indica una o más veces
* indica cero o más veces
? indica cero o una vez
() indica agrupamiento
| indica disyunción
, indica secuencia ordenada
Vamos pues a echarle un vistazo a nuestro ejemplo para ver eso qué implica.

<!ELEMENT empresa (nombre, url*, direccionPostal?)>
Según lo dicho antes, esta declaración define un elemento de nombre "empresa" que puede contener a su vez otros elementos, y sólo otros elementos, no puede tener texto plano; y además estos elementos tienen que ser de tipo "nombre","url" y "direccionPostal"; y además tienen que aparecer en este orden; y además ocurrirá que,
"nombre" aparecerá sólo una vez,
"url" puede aparecer cuantas veces quiera o no aparecer,
"direccionPostal" puede aparecer una vez o no aparecer

¿Fácil no? Ahora vamos con los atributos
Los atributos se declaran con !ATTLIST seguido del nombre del elemento al que pertenecen y seguido de la lista de atributos que puede contener este elemento.
La lista de atributos se escribe siguiendo triplas del siguiente modo
nombre_atributo tipo_atributo valor_por_defecto
Ocasionalmente puede ir entre el tipo de atributo y su valor por defecto la obligatoriedad o no de que aparezca el atributo, de modo que
#REQUIRED significa que el atributo es obligatorio
#IMPLIED significa que el atributo no es obligatorio
#FIXED significa que el atributo está fijo al valor que ponemos por defecto y el programador del documento xml no puede modificarlo. Si lo hiciera esta valor es ignorado prevaleciendo el del DTD.
El valor por defecto sólo tiene sentido cuando el atributo es #FIXED o #IMPLIED. En el caso concreto de #FIXED además es obligatorio. La cosa es que si ponemos a un atributo #REQUIRED se supone que es obligatorio, luego el programador pondrá un valor sí o sí, ¿para qué íbamos a darle un valor por defecto si siempre sería machacado por el del programador XML?
Los tipos de datos pueden ser:
CDATA -> Similar al #PCDATA de los elementos.
Enumerated -> Tienen su sintaxis especial, es el que hemos usado en el ejemplo para el atributo "tipo" del elemento "url". Consiste en una expresión de posibles valores separados por (|) donde el programador/a elegirá uno de ellos.
ID -> Asocia al elemento un identificador único.
IDREF -> Referencia a un ID.
IDREFS -> Lista de IDREF separados por espacio.
NMTOKEN -> Especifican identificadores.
NMTOKENS -> Especifican listas de identificadores.

Si todo esto lo aplicamos a nuestro ejemplo particular...
<!ATTLIST empresa
clase CDATA #REQUIRED
contacto CDATA #REQUIRED>

...implica que estamos tratando con la lista de atributos del elemento "empresa"; que además puede tener atributos tipo clase o tipo contacto; que además clase son datos normales y corrientes y es obligatoria su aparición; y que además contacto también tendrá como valores datos normales y será obligatoria su especificación en el documento XML.

<!ATTLIST url
tipo (web | blog | wiki | proyecto) "web">

...implica que estamos tratando con la lista de atributos del elemento "url"; que además sólo tendrá el atributo "tipo"; que éste podrá ser igual a "web" o "blog" o "wiki" o "proyecto" y que en caso de no encontrarse el valor por defecto será de "web".

Y bien, yo creo que como introducción a lo que puede ser XML y su definición mediante DTDs, ésto ya está. Ya podéis haceros vuestro lenguaje MiracomomoloML para definir todo lo que se os ocurra. ¿Y para qué? Pues por ejemplo una utilidad muy buena es la de pasarle al documento una hoja de estilo XSLT y transformarlo directamente en una página web con un formato determinado, que puede servirnos para crear páginas web dinámicamente en una máquina a partir de una aplicación que recoja unos datos de un formulario web, o para utilizar sistemas como DOM o JDOM para recorrer la información recogida en el formulario web y convertida a XML y usarla para hacer otra cosa, o para crear apliciones...¡yo qué se! yo ya os he contao como funciona, ahora ¡a buscarle utilidades propias, coño! :).

Espero que os sea de utilidad. Si así es, prometo volver para contaros un poco de XMLSchema, que vienen a ser los sucesores de los DTD y que permiten más versatilidad y especificidad en las definiciones.

+info:
http://www.w3.org
http://www.xml.com

http://www.xmlinfo.com

viernes, febrero 09, 2007

SMIL: HTML + TIME


En este artículo vamos a comentar brevemente la posibilidad de extender el HTML con líneas temporales, de forma que podamos definir acciones y movimientos dentro de una escala temporal. Esta técnica de programación permite una experiencia mucho más rica de nuestras aplicaciones o páginas web.

SMIL (Synchronized Multimedia Integration Language) es un lenguaje similar al HTML para implementar presentaciones audiovisuales. Empezó en 1997, estando actualmente en la versión 2.1 de su desarrollo. Es una recomendación del comité W3C aunque, inexplicablemente, no ha sido acogida por Firefox y si por Internet Explorer desde la versión 5.5.

¿Qué se puede hacer con SMIL?
Según W3C, las posibilidades de SMIL abarcan los siguientes items:
  • Creación de presentaciones para internet e intranets.
  • Creación de presentaciones tipo "slideshow"
  • Se ha descrito SMIL como la respuesta a PowerPoint en internet
  • Las presentaciones SMIL pueden mostrar múltiples tipos de ficheros (texto, video, audio,...)
  • Las presentaciones pueden mostrar múltiples ficheros al mismo tiempo.
  • Las presentaciones pueden mostrar ficheros de múltiples servidores web.
  • Las presentaciones pueden contener enlaces a otras presentaciones
  • Las presentaciones pueden tener botones de control (iniciar, parar, siguiente,...)
  • Se pueden definir secuencias y duración de acciones en el tiempo
  • Se puede definir la posición y visibilidad de los elementos

Realmente se pueden definir múltiples acciones de una manera fácil y sencilla mediante SMIL. El siguiente es un código de ejemplo de una acción sencilla realizada en SMIL:













Como se puede observar, el código está realizado en XML y es fácilmente entendible:
  • Todo el código se mete dentro de la etiqueta "smil"
  • Se le añade un "body" a la acción (como si fuera HTML)
  • La etiqueta define una secuencia que se repetirá indefinidamente "seq" (repeatCount="indefinite")
  • La secuencia se compone de dos imágenes que irán apareciendo, primero image1.jpg durante 3 segundos y después image2.jpg durante otros 3 segundos.

¿Cómo reproducir código SMIL?
El código SMIL se reproduce o ejecuta en visualizadores SMIL preparados para ello. Existen múltiples de ellos en internet, siendo los más destacados:
  • Ambulant Player: reproductor open-source que soporta la versión 2.1
  • RealOne: de RealNetworks
  • Grins: de Oratrix
  • Internet Explorer
Sin embargo, una de las posibilidades que más potencia nos da SMIL es la capacidad de integrarse con el HTML permitiendo definir líneas de tiempo para los elementos de las páginas.

HTML + TIME
Esta opción sólo está disponible para Internet Explorer puesto que es el único que sigue la recomendación del W3C. Al integrar el código SMIL junto con el HTML, podemos ampliar las propiedades de los elementos HTML con el tiempo. Al incluirles el factor del tiempo podemos realizar cambios en su visibilidad, movimiento, apariencia, comportamiento dependiendo del momento en el que nos encontremos.

Para habilitar esta función deberemos declarar lo siguiente:








Una vez importado el espacio de nombres, podremos incluirle la opción del tiempo a cualquier elemento que queramos en nuestra página. El siguiente código realiza una acción básica integrándose con HTML:








En este caso, definimos una secuencia temporal que se repetirá indefinidamente apareciendo una imagen y después otra. Es el mismo ejemplo que pusimos antes pero con HTML.

También podemos actuar sobre el inicio y el fin de las secuencias mediante la acción del usuario. En el siguiente ejemplo, la acción empezará 2 segundos después de que el usuario pulse sobre el botón "boton1" y terminará cuando el usuario pulse sobre el botón "boton2":

















En este código también se introduce la posibilidad de realizar acciones en paralelo. Ejecutamos la reproducción de un sonido en paralelo con la secuencia de dos imágenes.

Transiciones:
SMIL2.0 introduce la posibilidad de realizar transiciones entre elementos o en un elemento. De esta manera se introduce una mayor riqueza visual. Para incluir transiciones sólo tendremos que definirlas de esta manera:













Las transiciones posibles son:
  • Fade
  • barnDoorWipe
  • barWipe
  • clockWipe
  • ellipseWipe
  • fanWipe
  • irisWipe
  • pushWipe
  • slideWipe
  • snakeWipe
  • starWipe
Elementos Audiovisuales:
Los tags que definen elementos audiovisuales que se pueden manejar mediante SMIL en HTML son:
  • "animation"
  • "audio"
  • "brush"
  • "img"
  • "param"
  • "ref"
  • "text"
  • "textstream"
  • "video"

Conclusión:
SMIL nos ofrece una posibilidad muy buena de incluir animaciones y efectos en nuestras páginas web interactuando con los componentes HTML de una manera estándar.No necesitamos instalarnos ningún plugin ni herramienta de terceros y permite una interacción mayor con el usuario.