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.
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.
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.
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.
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>
</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: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"/>
</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>
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();">
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.