martes, 8 de enero de 2008

XSLT-XML y AJAX

Esta vez veremos como crear un resultado html utilizando plantillas creadas en xls y que a raíz de la conversión con xml generar un archivo de resultados final. Esto ha sido mencionado en reiteradas ocaciones en los artículos que he publicado en diciembre del 2007, así que si quieren sacar el mayor provecho, les recomiendo que vean estos.

Antes de realizar cualquier ejemplo tenemos que entender un poco que es XSLT, así que veremos una pequeña descripción que acontinuación detallamos:

XSLT (XML Stylesheets Language for Transformation o en español, Lenguaje de Transformación Basado en hojas de estilo) es utilizado para realizar una transformación de documentos XML a otro tipo de documentos de estructura de XML o a documentos finales, como es el caso del artículo que detallaremos, ya que, la transformación que realizaremos será a código HTML (Documento Final).

Aunque, existe una similitud en algunas de las sentencias de programación a las cuales estamos acostumbrados a utilizar, el comportamiento funcional de estas sentencias, están definidas para trabajar con las estructuras de los archivos XML que entregamos a la plantilla definida en XSLT, la cual genera el resultado final esperado.

He querido que veamos este tipo de generación de páginas Web o de resultados de HTML, debido a que nos pueden facilitar la vida enormemente, aunque cuando se empieza con XSLT nos podemos complicar un poco. Pero, al final, cuando se entiende la filosofía, nos pueden ayudar en gran medida, sobretodo cuando queremos trabajar con la misma lógica en diferentes presentaciones (páginas o sitios enteros), ya que esto nos permite modificar las plantillas y mantener la lógica de programación generada, es decir, hasta la entrega del XML todo sigue igual.

Adicionalmente nos permite realizar llamadas asincrónicas sea con AJAX o AJAXPRO, en donde se nos retorna un resultado formateado, incluso con las imágenes definidas. Se debe destacar que con AjaxPro, si se está trabajando con estructuras de objetos, los retornos de información deben ser serializados, lo cual es más seguro al momento de transmitir información desde el servidor al cliente.

Si bien es cierto, existen muchos sitios en donde pueden encontrar información de cómo trabajar con XML y XSLT. A continuación, les voy a entregar unas URL muy buenas que a mi me sirvieron mucho, al momento de trabajar en un proyecto desarrollado con estas tecnologías.

Para los que recién parten con XSLT pueden ir a:
http://www.zvon.org/xxl/XSLTutorial/Output/example1_ch1-html Aquí podrán encontrar de forma simple, explicaciones de cómo definir archivos en XML y como deben ser tratados en XSLT para obtener el resultado final.

Para los que les gusta buscar en MSDN, también existen ayudas en línea. Aquí les entrego una URL que les permitirá realizar las transformaciones entre XML y XSLT:http://support.microsoft.com/kb/307494/es

Para los que tienen idea de XSLT, pueden dirigirse a:
http://xml.utilitas.org/xslt_mini_como_htmlç Aquí podrán encontrar con más detalle como poder utilizar las funciones y objetos que ofrece XSLT.

Antes de empezar con el ejemplo, me gustaría detallar que, el pasarle al servidor la carga de generación de código HTML en solicitud a un método definido en AJAX, que responda a esta solicitud, resulta mucho más optimo que retornar la información de datos y luego trabajar con JAVASCRIPT para desplegar la misma.


Ventajas.


Si se manejan bien con JavaScript, pueden retornar un HTML con paginación incluida, ya que pueden no solo retornar HTML puro y duro, sino que también en el, pueden incluir funciones de cliente.

Respuesta rápida a la generación de zonas que desea refrescar.


Desventajas


El Historial se pierde, no queda registrado, pero si tienen paciencia y siguen el ejemplo hasta el final veremos como hacer un truquito para manejar el historial para AJAX y AJAXPRO sin necesidad de utilizar algún tipo de herramienta, ya que solo en AJAX existe un control History en el Framework de Ajax de Futures, pero esto nos obliga a manejar muy bien los eventos y generalmente a utilizar controles de AJAX prediseñados, pero si deseáramos generar nuestras propias funciones tendríamos que tener muchas consideraciones para incluir el control History.

Ejemplo

Como ya sabemos, debemos crear una solución y a esta asociar una referencia a la librería de AJAX que utilizaremos, en este caso Ajax.dll (Recomiendo crear el directorio bin en el proyecto y copiar la dll en este).

Como siguiente paso, agregaremos en el WEB.CONFIG, dentro del nodo system.web, las siguientes líneas, las cuales nos permitirán realizar la referencia a la dll de AJAX que hemos referenciado.

<httpHandlers>
<add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax"/>
</httpHandlers>


A continuación, Crearemos un nuevo archivo .aspx que llamaremos AjaxXslt.aspx, definiendo el código html de la siguiente forma:


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Manejo de XSLT con Ajax </title>
&lt/head>
<body>
<form id="frm" runat="server">
<div id="divSeleccion" >

</div>
</form>
</body>
</html>


Agregaremos un nuevo archivo del tipo XSLT al proyecto, que llamaremos despliegue.xslt. Como ven, se genera automáticamente un archivo con un cuerpo de HTML.


Como nosotros solo vamos a trabajar con un archivo, podemos definir un template de despliegue y según una opción podremos llamar a este template o a otro, en este caso crearemos un template que llamaremos empleados y que despues lo referenciaremos desde el cuerpo del template match, como se muestra a continuación:


<?xml version="1.0" encoding="ISO-8859-15>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">

<xsl:if test="root/parametro/opcion=1">
<xsl:call-template name="empleado"/>
</xsl:if>

</xsl:template>

<xsl:template name="empleado">
<select id="sltEmpleado" >
<xsl:for-each select="root/empleado">
<option>
<xsl:attribute name="id">
<xsl:value-of select="id"/>
</xsl:attribute>
<xsl:value-of select="apellido"/>
</option>
</xsl:for-each>
</select>
</xsl:template>
</xsl:stylesheet>


Comentemos el código generado:


El cuerpo principal de un archivo XSLT está encerrado en el match, nunca se puede generar un archivo xslt sin tener definida la directiva match, es desde aquí donde se inicia la generación del archivo de resultado.

Aunque es posible realizar llamadas a archivos xslt fuera del la directiva macth, los template que estén contenidos en estas plantillas solo podrán ser ejecutadas dentro de dicha directiva, el ejemplo más claro es el de nuestro template empleado que lo hemos agregado fuera de la directiva match, pero que se llama su ejecución dentro de este.

Ahora si bien es cierto podemos ver que dentro del cuerpo del match existe un if, este testea un valor de un nodo del xml que se debe entregar, por lo cual en el xml que entreguemos debemos considerar que existan estos nodos.

Si observan, en el template empleado existe un select que se cargará mediante un for-each, este se ejecuatrá mientras existan registros en el nodo root/empleado, es decir, si existen 10 nodos empleado, el for-each se ejecutará 10 veces.

Por otra parte, cuando cargamos los datos, vemos que agregamos los atributos al nodo del select (opcion) utilizando la opcion de xslt attribute. Esta opción puede ser utilizada para todos los tipos de atributo que existen en los controles HTML.

La información que se agrega a estos atributos se entrega desde el archivo xml, ahora ustedes se preguntarán de doonde sale este archivo xml, bueno ahora vamos a generarlo y esto se hará desde el ajaxmetodo de la siguiente forma.

Primero debemos instanciar los espacios de nombre:
using System.Data;
using System.Data.SqlClient;
using System.Xml;

Luego, en el método que atiende el evento load de la página que hemos creado agregaremos la siguiente línea de código:

protected void Page_Load(object sender, EventArgs e){
Ajax.Utility.RegisterTypeForAjax(typeof(AjaxXslt));
}

Antes de continuar, debemos detenernos a ver que vamos a hacer el despliegue. En este caso debemos realizar una consulta a la base de datos y retornar un archivo con el esquema xml, para ello utilizaremos la sentencia de sql for xml explicit, que me permitirá devolver un esquema en xml, luego el resultado debemos cargarlo en una variable de tipo string, que nos permitirá concatenar las otras opciones del xml, estas acciones se muestran a continuación:

[Ajax.AjaxMethod()]
public String getEmpleado() {
String strResultado = "";
try{
XmlDocument xml = new XmlDocument();

System.Text.StringBuilder strTxt = new System.Text.StringBuilder();

strTxt.Append("<root>");
strTxt.Append("<parametro>");
strTxt.Append("<opcion>1</opcion>");
strTxt.Append("</parametro>
");
strTxt.Append("</root>
");

xml.LoadXml(strTxt.ToString());
String strCnx = "Data Source=(local);Initial Catalog=Northwind;Integrated Security=True";

String strSql = "select 1 as tag, null as parent, EmployeeID as [empleado!1!id!element], " +
"LastName as [empleado!1!apellido!element] " +
"from Employees for xml explicit";

SqlConnection cnx = new SqlConnection(strCnx);
cnx.Open();
SqlCommand cmd = new SqlCommand(strSql, cnx);
SqlDataReader rdr = cmd.ExecuteReader();

String strDato = "";
while (rdr.Read()){
strDato += rdr[0].ToString();
}

xml.LastChild.InnerXml = xml.LastChild.InnerXml + strDato;

System.IO.StringWriter swHtml = new System.IO.StringWriter();
System.Xml.Xsl.XslCompiledTransform xsl = new System.Xml.Xsl.XslCompiledTransform();

xsl.Load(HttpContext.Current.Server.MapPath("~") + "\\despliegue.xsl");

xsl.Transform(xml, null, swHtml);
strResultado = swHtml.ToString();

swHtml.Close();
cnx.Close();
}
catch (Exception ex){
throw ex;
}
return strResultado;
}


Comentemos el código creado.


Como vemos en el código desplegado, ahora no devolvemos un Dataset sino que devolvemos un resultado entre el XML que generamos y el archivo XSLT que creamos con anterioridad, el cual entrega directamente el select de html con la información.

Para ello primero creamos una variable de tipo xml y vamos agregando a esta los nodos que vamos creando. Se debe tener cuidado cuando se realiza un InnerXml ya que este tipo de opciones si no se suma, reemplaza a los nodos ya creados.

El siguiente paso, una vez construido el archivo XML, es crear una variable para realizar la transformación a la cual le entergaremos el path en donde se encuentra el archivo xsl que utilizaremos para generar el código, por ultimo, utilizando el método Transform cargamos a una variable de tipo StringWriter el resultado entre el cruce de los archivos.

Ahora lo que nos queda es realizar la llamada desde el cliente, para ello crearemos las siguientes funciones en javascript en la zona de script que definiremos, de la siguiente forma:

<script language="javascript">
function getEmpleado(){
AjaxXslt.getEmpleado(getEmpleado_callback,
document.getElementById("divSeleccion"));
}

function getEmpleado_callback(res) {
if (res.error!=null){
alert(res.error);
}else{
res.context.innerHTML = res.value;
}
}

</script>

Como se observa, hemos creado ahora en el cliente dos funciones, que no muestran ningún tipo de lógica de negocio, solo el despliegue de datos del resultado entregado, es aquí en donde pasamos la carga de generación al servidor, pudiendo incluso, como comente anteriormente, realizar paginación. Esto, dependiendo del tiempo que tenga, podríamos verlo en futuros artículos.

Por ultimo, nos falta realizar la llamada inicial, para ello, en el body agregaremos en la sentencia onload, la siguiente llamada a la función definida en javascript.

<body onload="javascript:getEmpleado();">


Resumen

Como se ha observado, este tipo de transferencia de datos es más complejo y representa un mejor resultado al momento de realizar un despliegue en el cliente, debido a que el resultado es generado en el servidor y solo en el cliente se despliega el resultado. El problema de esto es que como son controles de html los que se generan al realizar un cambio de dato en el combo desplegado, no queda refrescada esa acción en el history del navegador ya que no se realiza una solicitud al servidor direcatmente. Una forma de poder manejar las solicitudes del history la veremos más adelante en el artículo de manejo del historial.


volver

No hay comentarios: