Programación

Guía de buenas prácticas para aumentar el rendimiento de jQuery

JQueryLlevo tiempo con ganas de escribir esta guía de buenas prácticas para aumentar el rendimiento de jQuery y de javascript en general. Uno de los principales problemas que nos encontramos por internet son que hasta hace un tiempo, cada javascript era de su padre y de su madre, por lo que perdía importancia dentro del desarrollo web y no optimizando esta parte del código. Con la inclusión de nuevas ideas a la hora de desarrollar webs y la aparición de multitud de frameworks como jQuery, mootoolssproutcore, hacen que el código javascript que escriben los desarrolladores, funcione en todos o casi todos los navegadores, pero aún así, algo falla.

Aunque ya no es como pasaba antiguamente que al entrar en una web o tenías Internet Explorer o podías olvidarte del javascript y por tanto de una gran parte de funcionalidad en la web, hoy en día esto no pasa gracias a los frameworks de javascript, es cierto que hay un problema y es el rendimiento. En este artículo me quiero centrar en el framework mas extendido, que es jQuery y una breve guía de como aumentar el rendimiento de jQuery y por tanto aumentar el rendimiento de javascript.

A continuación, detallo un listado de buenas practicas para aumentar el rendimiento de jQuery.

 

1. Acceder a id’s y no a clases

Cuando vemos algun ejemplo de jQuery, siempre se nos muestra con $(«.clase»).html(«prueba»), esto es un ejemplo que nos lleva a cometer grandes faltas de rendimiento cuando trabajamos con un proyecto muy grande. Aunque a veces no nos queda mas remedio que acceder a clases, su uso dentro de los selectores de jQuery, debemos de evitarlo siempre que podamos, ya que al acceder por clase, jQuery buscará en todo el código esa clase, todas las veces pueda, sin embargo, si utilizamos un id, al encontrar la primera coincidencia, la búsqueda parará y por tanto la ejecución será mas rápida.

$(".clase").html("prueba"); //es mas lento
$("#id").html("prueba"); //es mas rápido

 

2. Utilizar selectores dobles en jQuery

Hace poco tiempo escribí un artículo sobre el uso de selectores dobles para aumentar el rendimiento en jQuery. Básicamente y sin entrar mucho en detalle, ya que para ello hay ya un articulo dedicado, un selector doble lo que hace es crear un contexto donde buscar el selector. Imaginemos que queremos cambiar el html  de un menú (si es un absurdo) para ello, en lugar de ejecutar:

$(".menu").html("jodimos el menú");

Lo ideal es usar un contexto con base a un id, donde jquery tenga que buscar menos cantidad de datos

var header = $("#header");
$(".menu", header).html("jodimos el menú");

De esta forma, capturamos un contexto y le decimos a jQuery que busque solo en ese contexto en lugar de en toda la web, por lo que la ejecución de un selector de clase, será mas rápida.

 

3. Cachear variables que mas utilicemos y de contexto

Cuando escribimos código de jQuery, es normal que recurrentemente accedamos a ciertas partes de la página, que como hemos visto en el ejemplo anterior, utilizaríamos variables de contexto. Para agilizar la carga, es recomendable cachear estas variables, para que no tengamos que buscarlas cada vez que vayamos a utilizarlas:

var header = $("#header");
var footer = $("#footer");

.....

function bordemenu() {
    $(".menu", header).css("border", "solid 1px #000000");
}

De esta forma, no buscamos header, sino que accedemos a la misma variable que cargamos al cargar la página. Incluso, si ya sabemos de antemano que vamos a acceder muchas veces al menú, podríamos cachearlo también.

 

4. Evitar el uso de each

En jQuery, la función each no es más que un foreach que nos devuelve los nodos que hemos seleccionado. Es por esto que debemos de intentar, en la medida de lo posible, no utilizar este método para no ejecutar un foreach e intentar recorrer los nodos con un for, que aunque un poco mas complejo, su ejecución será mas rápida.

 

5. Centralizar la carga de eventos

Cuando hacemos una aplicación web muy muy grande y con mucho uso de ajax, nos damos cuenta de que cada vez tenemos mas y mas eventos y que como nos descuidemos, acabamos escribiendo casi los mismos eventos en multitud de sitios. Es por ello, que es recomendable tener una o varias funciones donde incialicemos los eventos para su carga y ejecución. Parece una tontería, pero a la larga, mas que en rendimiento, nos favorecerá en rendimiento a la hora de escalar nuestra aplicación, aunque también evitará la duplicidad de eventos sobre un mismo objeto y por tanto la ejecución será mas rápida.

 

Estos son 5 sencillos casos en los que podemos aumentar considerablemente la velocidad de ejecución de una web utilizando jQuery. Quizás, haciendo sencillos ejemplos, no seamos coscientes de esa diferencia de velocidad, pero en una macroaplicación que mueve multitud de datos asíncronamente, nos daremos cuenta que estas practicas agilizarán la página en general y agilizarán jQuery.

Selectores dobles con JQuery, aumentando el rendimiento de JQuery

JQueryA menudo suele pasar que al comparar diferentes librerías de Javascript, se habla de JQuery como una librería de muy fácil manejo por utilizar selectores DOM y de CSS pero a la vez se dice que por esto es mas lenta que el resto. Mi objetivo con este artículo no es explicar los diferentes tipos de selectores de JQuery sino como aumentar el rendimiento de JQuery utilizando selectores dobles de contexto.

En JQuery aparte de otras formas como objetos DOM y similares, lo normal es realizar un selector apuntando a una clase de CSS o un id. Antes de nada, comentar que el uso de clases en los selectores de JQuery, es recomendable omitirlo siempre que sea posible (no siempre se puede), ya que JQuery espera encontrar varios nodos y por tanto evaluará todo el código, por lo que es mas lento que utilizar ids, que una vez lo encuentre, dejará de buscar. Tras este miniconsejo de rendimiento de JQuery, me gustaría comentar como funcionan los selectores dobles de contexto de JQuery.

Normalmente  para hacer una selección en JQuery, hacemos algo tal que $(«selector») y seleccionamos el objeto de JQuery. Un selector doble o selector de contexto es básicamente una especie de cache, un contexto donde buscar ese selector pero no en toda la página, sino en una parte de esta. Para utilizar un selector doble o selector de contexto, lo que hacemos es enviarle un parámetro extra a la consulta de selección. En mi caso me gusta enviar un objeto de JQuery que intento cargar en memoria al cargar la página, sacrificando tiempo de carga por velocidad a la hora de interactuar con la propia página. Para utilizar un selector doble o selector de conexto lo que hacemos es por ejemplo hacer $(«selector», objetopreseleccionado), de esta forma, JQuery no buscará el selector en toda la página, sino que se centrará en el contexto donde se encuentra lo preseleccionado.

Para que todo quede un poco mas claro, voy a poner un ejemplo, partamos de la idea que tenemos la página partida en 4 sectores, una cabecera, un contenido dividido en menú lateral y contenido en si, y un pie. Todas estas partes cambiarán dinámicamente, así que al realizar el document ready cargaremos en variables las diferentes secciones de la web con la idea de realizar operaciones de una forma mas rápida y consumiendo menos recursos de procesador al cliente, que ya sabemos que el javascript puede ralentizar mucho una página si no se hace con cuidado.

var header, footer, menu, content;

$(document).ready(function($) {
  header = $("#header");
  footer = $("#footer");
  menu = $("#menu");
  content = $("#content");
}

Una vez que hemos cargado en memoria las diferentes secciones de la web, podremos trabajar con eventos, modificaciones y efectos de una manera mucho mas eficiente, realizando las llamadas utilizando en los selectores esas variables como contexto de JQuery.

$("#logo", header).html("mi html");
$(".article a", content).click(function() { .... });

Si utilizamos los selectores de JQuery como en el ejemplo anterior, usando un contexto para la búsqueda, ahorraremos muchísimo tiempo de proceso porque JQuery no tendrá que buscar en todo el documento, sino que lo realizará en base al contexto que le indiquemos. Quiero aclarar que como todo, hay que estudiar cuando usar o no usar contextos, ya que si la página es muy pequeña no merece la pena cargar en memoria las diferentes secciones, pero si la página es bastante grande y con muchos datos, podemos acelerar el uso de JQuery y aumentar el rendimiento de JQuery en un 250%.

Por qué usar StringBuilder en lugar de concatenar Strings

Ando un poco liado y llevo una temporada sin escribir. Hay un apunte, que es común para varios lenguajes que son Java y por ejemplo .Net, tanto Visual Basic .Net y C#, así como el resto de lenguajes de la plataforma .Net que es la clase StringBuilder. Hay gente que no sabe por que o cuando utilizar la clase StringBuilder y realmente es uno de esos pequeños detalles de buenas prácticas, que a simple vista en un proyecto pequeño no se aprecian, pero cuando entre manos tenemos un gran proyecto que recibe millones de peticiones diarias, estas pequeñas nuevas practicas pueden suponer un gran referente de ahorro en el consumo de memoria y procesador de un servidor.

Tanto en Java como en .Net, cuando creamos un nuevo String, instanciamos un objeto String en una variable, cuando con la sentencia «+=» vamos concatenando mas texto, lo que hacen estas plataformas es crear una nueva instancia del objeto con la concatenación de las dos variables de texto. Por otro lado, cuando tenemos un StringBuilder instanciamos una clase StrringBuilder, llamando al método «append» en Java y «Append» en .Net, lo que hacemos es realizar una concatenación real de texto en el buffer de texto para luego instanciar un nuevo objeto String cuando llamemos al método «toString» en Java y «ToString» en .Net. A simple vista parece una tontería, cuando tenemos un texto que concatenamos 2 o 3 veces, realmente no merece la pena generar un StringBuilder, pero cuando concatenamos repetidamente texto varias veces el rendimiento es mayor si utilizamos StringBuilder, ya que si tenemos 20 concatenaciones seguidas, utilizando Strings normales concatenados, tendríamos 20 instancias de objetos, mientras que con StringBuilder solo 2. Como he dicho antes, en un pequeño proyecto, esto es prácticamente inapreciable, pero cuando tenemos un proyecto que recibe millones de peticiones diarias, algo tan tonto como utilizar concatenaciones de texto o StringBuilder puede suponer tener que añadir mas memoria al servidor para soportar tantas instancias de objetos e incluso un procesador mas potente para soportar el paso del recolector de basura para tantos objetos instanciados, esto en el mejor de los casos, si no llegamos al caso de tener que añadir un servidor al cluster para soportar todo esto.

Un cumulo de buenas practicas pueden suponer un gran ahorro de recursos, que se traducen en ahorro de dinero, cuando se trata de grandes proyectos.

Diferentes formas de seleccionar etiquetas hijas en css

Cuando estamos maquetando una web, muchas veces nos vemos en la necesidad o en la comodidad de aplicar estilos a etiquetas o clases hijas directamente pero a veces esto puede convertirse en un problema. Normalmente cuando se maqueta se suele seleccionar directamente todas las etiquetas hija de un tipo por ejemplo, todos los p que haya dentro de un div con una clase, pero que pasa si tenemos una estructura un tanto compleja y no queremos que todas se comporten de una misma manera, como por ejemplo usando listas y sublistas y queremos que las sublistas tengan un margen que la lista normal no queremos que tenga.

En CSS hay varias formas de seleccionar etiquetas hija, la mas común es la de seleccionar todos los hijos de un tipo, como seria el ejemplo:

.clase ul {
    margin: 0px;
    padding: 0px;
    list-style: none;
}

Con esto decimos que todos los li contenidos dentro de un ul, tengan un estilo, pero ¿Y si queremos hacer un listado mas complejo, con sublistados? Lo que debemos de hacer es decirle que aunque los li dentro de ul se comporten de una forma concreta, los primeros li queremos que se comporten de otra forma. En el siguiente ejemplo se usa para formar un listado con li y ul donde queremos que los primeros li no tengan margen alguno, pero que el resto de li que haya tengan un margen a la izquierda para simular un sangrado automático:

.sidebarBox ul > li > ul {
    margin-left: 25px;
}

Y el html sería el siguiente:

  • lista1
    • lista2

Con esto lista1 no tendra sangrado pero lista2 tendra un sangrado de 25px hacia la izquierda. Espero que os sirva de ayuda.

Publicada la versión 0.2 de puntoengine

He publicado la nueva versión de Punto Engine PHP, o PEP en su versión 0.2. Esta versión trae importantes mejoras con respecto a la versión anterior, ya que administra mucho mejor el sistema de templates para poder hacer páginas dinámicas mucho mas fácil y rápido. Entre las mejoras cabe destacar:

  • Añadido un archivo de changelog para poder ver las modificaciones.
  • Ahora el Kernel permite recuperar la ruta virtual (la que accede desde el navegador) aparte de la ya implementada ruta física.
  • Los Servlet tienen ahora un atributo de url para poder realizar controles si fuera necesario.
  • En el web.xml se puede configurar el modo debug para poder tener una traza mas detalla del error que se produjo.
  • En el Servlet se ha añadido un atributo debug para en caso de desarrollo, poder realizar trazas si se desea.
  • El metodo SendRedirect para redireccionar la pagina hacia otra, ahora tiene una funcionalidad como .Net donde si añadimos la clave «~/» al principio de la url, esta sera sustituida por la url del proyecto.
  • Ahora los Servlets pueden tener una MasterPage para tener un template base desde el que cargar el contenido.
  • En los templates, si ponemos la clave «~/» en un enlace, css o similar, sustituira esta por la ruta del proyecto.
  • Se han cambiado los mensajes que aun aparecian en los errores de «IDCS Server» por «Punto Engine Server».
  • Se ha cambiado el HomeController por TestController y se han añadido diferentes funcionalidades de MasterPage y diferentes ejemplos a mostrar para ver su funcionamiento.
  • Se ha corregido un error que provocaba que cuando se lanzaba una excepción no fatal, se seguian mostrando otros errores encadenados.
  • Se ha borrado temporalmente el acceso mediante web.xml al PepAdmin ya que es aun no es funcional.

Las mejoras de esta versión son bastante importantes y permiten un desarrollo mas fluido de las páginas. Para quien quiera descargarlo puede hacerlo entrando en la web del proyecto puntoengine.

Namespaces o espacios de nombre virtuales en javascript

En la mayoría de lenguajes de programación relativamente maduros o potentes, existe lo que denominamos namespace o espacio de nombres. Los namespace no son otra cosa que unos contenedores de nombre donde podremos contener clases, funciones y variables que pueden repetirse con el mismo nombre en otros espacios de nombre o namespace sin que ello suponga un error. Un ejemplo claro de cual es la verdadera utilidad organizadora de los namespace o espacios de nombres es en las librerías gráficas de los lenguajes de programación, ya que en estas librerías un elemento muy común suele ser la clase Window que hace referencia a una ventana pero que puede estar dentro de GTK, QT, .Net, API de Windows, etc. (esto no es muy correcto puesto que GTK seria GTKWindow pero es por poner un ejemplo). Javascript, como un lenguaje ya mas que maduro con el paso de los años y relativamente estandarizado por los navegadores modernos, pese a ser un lenguaje de programación multiparadigma, al igual que haga PHP, también tiene namespaces o espacios de nombre, aunque debido a la debilidad de las variables estos namespaces son mas virtuales que reales.

Entendiendo que es y para que sirve un namespace, para declararlo en javascript, lo que debemos de hacer es utilizar arrays para generarlo. Gracias a la debilidad y dinamismo de las variables en javascript, podemos asignar a una variable un array de posiciones por nombre y acceder a estas mediante un signo de puntuación «.» y no por su clave común de array [«clave»], por lo que aquí es donde viene el truco. Básicamente lo que hacemos al declarar un namespace en javascript es asignar a un variable un array con las posiciones del namespace y luego ya dentro de estas posiciones, acceder como si desde .Net o Java se tratase. Con un ejemplo se ve mas sencillo.

var Indalcasa = { Utilidades : {} };

Indalcasa.Utilidades.MiClase = function() {
  this.variable = "valor";

  this.metodo = function(parametros) {
    return this.variable + " " + parametros;
  }
};

var iClase = new Indalcasa.Utilidades.MiClase();
iClase.variable = "nuevo valor";
alert(iClase.metodo("prueba"));

El ejemplo anterior mostrará una ventana de alert con un mensaje tal que «nuevo valor prueba», ya que hemos instanciado la clase, le hemos cambiado el valor al atributo de la clase y en el método de la clase, concatenamos el valor del atributo de la clase al parámetros que hemos pasado. Esto es un pequeño y sencillo ejemplo de lo que se puede hacer con javascript, namespaces y clases.

Publicada la version 0.1.1 de puntoengine

Ayer publiqué la versión 0.1.1 de puntoengine. Puntoengine o Punto Engine PHP acortado PEP, es un framework en fase alfa para PHP del tipo MVC o Modelo Vista Controlador. Este framework basa su funcionalidad en una mezcla de diferentes frameworks web como son ASP.Net, Java Servlets y PHP en un antiguo framework propio llamado RLM Engine. Actualmente, pese a estar en una fase de desarrollo muy verde, pero ya es completamente operativo y se pueden construir webs con un sistema de Servlets como se haría una web en Java. La versión 0.1.1 en su revisión 7 de puntoengine se trata de la versión ya publicada 0.1.1 de puntoengine pero con la documentación completa del código, lo que facilita a quien quiera ver y estudiar el código y su funcionamiento, que sea mas fácil de seguir. Para la versión 0.2 de puntoengine se espera la creación de un administrador, actualmente en fase de desarrollo para poder gestionar entre otras cosas los Servlets instalados y la preparación para futuros plugins como puede ser el sistema de CMS.

Este es un proyecto a largo plazo y muy ambicioso que espero llegue lejos y pueda utilizarlo para construir diversas webs que tengo en mente. Según un calculo realizado siguiendo el sistema COCOMO, actualmente el proyecto con casi 1500 lineas de código, tendría un coste privado de unos 6.000€. Para el que quiera echar un vistazo e incluso colaborar con el desarrollo, documentación o aportando incidencias, puede hacerlo en la web del proyecto puntoengine.

Convertir un texto a mayusculas (toUpper) o minusculas (toLower) con transformadas xslt

Muchas veces, cuando necesitamos manipular texto desde transformaciones xsl, nos encontramos con el caso de que tenemos un texto en mayúsculas o un texto en minúsculas y queremos convertirlo a minúsculas o mayúsculas respectivamente. En cualquier lenguaje, solemos tener métodos para hacer un ToUpper, strtoupper o por el contrario ToLower, strtolower y similares, pero en xsl, al ser tan genérico, no disponemos de ese tipo de funciones, aunque si deberían de estar.

Para suplir esta necesidad, me he creado 2 funciones muy útiles que utilizan la funcion traslate, que comentare en otro articulo. Básicamente lo que hacemos es intercambiar una cadena por la otra en base a lo que va entrando por un texto. Con estas funciones podemos llamar a StringToLower o StringToUpper como si de un template normal se tratase, indicandole el texto que queremos convertir a mayúsculas o convertir a minúsculas y automáticamente nos convertirá la cadena.

El código seria el siguiente:

<!-- Variables globales -->
<xsl:param name="lower" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:param name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
 
<!-- Convierte una cadena de texto, todo en minusculas -->
<!-- @param string text Cadena a convertir a minusculas -->
<!-- @return Cadena en minusculas -->
<xsl:template name="StringToLower">
  <xsl:param name="text"/>
  <xsl:value-of select="translate($text,$upper,$lower)"/>
</xsl:template>
 
<!-- Convierte una cadena de texto, todo en mayusculas -->
<!-- @param string text Cadena a convertir a mayusculas -->
<!-- @return Cadena en mayusculas -->
<xsl:template name="StringToUpper">
  <xsl:param name="text"/>
  <xsl:value-of select="translate($text,$lower,$upper)"/>
</xsl:template>
 
<xsl:call-template name="StringToLower">
  <xsl:with-param name="text"
      select="'Mi texto que quiere ser Reemplazado a minusculas'" />
</xsl:call-template>
<xsl:call-template name="StringToUpper">
  <xsl:with-param name="text"
      select="'Mi texto que quiere ser Reemplazado a mayusculas'" />
</xsl:call-template>

El resultado de esta tranformacion del StringToLower seria «mi texto que quiere ser reemplazado a minúsculas» y la segunda llamada con el StringToUpper seria «MI TEXTO QUE QUIERE SER REEMPLAZADO A MAYUSCULAS». Esto es algo muy útil para trabajar con textos.

Descodificar Quoted Printable para leer correos de GMail en Visual Basic

Un amigo esta realizando un proyecto en Visual Basic .Net, que entre otras cosas se conecta a GMail para recibir correos e introducirlos en una base de datos para mostrarlos en un panel de administración. Hasta aquí todo normal, el problema viene cuando en los correos utiliza caracteres, que vamos a llamar extraños, como tildes por ejemplo. Cuando recibimos por código un mail que por ejemplo contenía la cadena «conexión», este texto no se nos devuelve así, sino que nos devolvería «conexi=F3n» y he aqui el problema, ya que esto no es codificación normal de UTF-8 a ASCII o similares sino que es completamente diferente.

Los servidores de correo utilizan protocolos bastante antiguos, en los que todo se basta en texto. Para separar encabezados se utilizan saltos de linea tipo «rn» o «n» y por ejemplo para adjuntar archivos hay que declarar una marca y decirle que el contenido del archivo esta entre marca y marca. Como no, todo esta basado en texto ASCII por lo que los caracteres extraños, letras con acento, eñes y similares, suelen encontrarse en una codificación que se llama «Quoted printable».

Quoted Printable o simplemente acortado QP es un sistema de codificación de 8 bits compatible con ASCII que basa su codificación de caracteres extraños en un formato de un símbolo igual seguido de 2 posiciones hexadecimales. Se rige por el estándar RFC-1345. Aunque algunos lenguajes traen incorporado por defecto funciones o librerías para codificación y descodificación de caracteres, .Net no tiene nada para descodificar este tipo de codificación. A continuación os mostrare un ejemplo de función de Visual Basic para la descodificación de estos caracteres, que básicamente recoge estos caracteres hexadecimales, los convierte a entero y obtiene el caracter de ASCII extendido de 255 caracteres, no el tradicional de 128 caracteres. De esta forma, obtendrá el carácter correcto ya traducido. Os dejo el ejemplo de la función:

Función de descodificación de cadenas de texto Quoted Printable

Public Shared Function QuotedPrintableDecode(ByVal text As String) _
As String
  Dim i As Integer
  Dim DecodedString As StringBuilder
  Dim Chars As Char()
  Dim CharsValue As String
  Dim HexValue As Integer

  Chars = text.ToCharArray()
  DecodedString = New StringBuilder

  For i = 0 To Chars.Length - 1
    If Chars(i) = "=" Then
      CharsValue = Nothing
      HexValue = Nothing

      If Chars(i + 1) = "0" Then
        CharsValue = Chars(i + 2)
      Else
        CharsValue = Chars(i + 1) & Chars(i + 2)
      End If

      HexValue = Val("&H" & CharsValue)

      If CharsValue.ToUpper = Hex(HexValue) Then
        DecodedString.Append(ChrW(HexValue))
        i += 2
      Else
        DecodedString.Append(Chars(i))
      End If
    Else
      DecodedString.Append(Chars(i))
    End If
  Next

  Return DecodedString.ToString
End Function

Ahora solo hace falta llamar a esa función pasando la cadena a convertir:

Public Shared Sub Main()
  Dim text As String = "conexi=F3n"
  Console.WriteLine(Application.QuotedPrintableDecode(text))
End Sub

El resultado de aplicar esto seria la cadena «conexión». Para que funcione es necesario importar el namespace System.Text, pero solo para el StringBuilder

Imports System.Text

Espero que os sirva de ayuda.

Centrar texto verticalmente con css

Desde hace años que me pase a las capas abandonando la maquetación en tablas, si algo he hechado de menos siempre ha sido el «como centrar texto verticalmente sin valign». Para solucionar este problema, siempre he usado subcapas con margin o paddings o directamente padding superior en la capa padre para bajar el texto, aunque eso se comporta de manera distinta dependiendo del navegador. En una pagina que estoy montando me he puesto a investigar, como alguna vez hago con el intellisense mirando todo lo que me encuentro y en esta ocasión le ha tocado el turno al css. Buscando me he encontrado con un atribuo de css que se llama line-height, que agranda la linea del texto a la altura que le indiquemos, lo que quiere decir que si tenemos un menú, de pastillas de 50px de alto y le indicamos que el line-height es 50px, el texto aparecerá centrado. Realmente no es algo milagroso ya que no es dinámico, pero para menús y cosas así viene genial.

Os dejo un ejemplo de como se utilizaría:

Ejemplo del html:

Ejemplo del css:

#menu {
  height: 50px;
}

.menuOption {
  line-height: 50px;
  text-align: center;
}

Con este ejemplo anterior, nos dibujaría una pastilla (mas o menos) y nos dejaría el texto centrado verticalmente y ya de paso centrado horizontalmente también.

Como dar formato a un número en xslt: format-number

Para los que o bien nos guste, o bien nos vemos obligados a usar transformadas xslt a veces en exceso, muchas veces nos encontramos con algunos problemas como son los números. Cuando debemos de hacer operaciones que van mas allá de sumar y restar dentro de una transformada xslt, nos encontramos muchas veces con un gran problema al mostrar los resultados de las operaciones. Por ejemplo, un caso practico (el mio de hoy, aunque me pasa desde que empecé a trabajar con xslt), ha sido que tengo que mostrar un combo (select) con maletas, pero cuando el trayecto es español, como no, al precio de esas maletas (incluido en el combo) hay que añadir un 7% de iva. Al proceder a esto, muchas veces me aparecen números que son auténticos chorizos, por ejemplo 37.000000004€, por lo que queda un poco feo en un combo. La solución es dar formato al numero/variable y dejarlo truncado a 2 decimales.

Para dar formato a un numero en una transformada xslt, podemos utilizar la función nativa de xslt format-number. Esta función cuenta con 2 parámetros, un primero que especificamos el numero a dar formato y como segundo parámetro que especifica cual sera el formato que se le dará al numero. La función tendría un formato tal que:

/**
 * Función de xslt nativa e independiente del lenguaje, ya sea java, .Net, php, etc. para dar formato a un numero desde XSLT
 * pero a veces puede provocar algún que otro fallo dependiendo del lenguaje que la implementa.
 * @param number Numero a dar formato
 * @param format Formato que se le dará, se utilizan los caracteres ('0', '#', '.', ',', '%')
 * @return Numero con su formato especificado
 */
string format-number(string number, string format)


Para dar formato, podemos utilizar los siguientes caracteres:

  • ‘0’: Los ceros, indican dígitos obligatorios, ignorando los ceros a la izquierda o derecha si son en la parte entera o decimal. Si por ejemplo tenemos el 34 y le aplicamos como formato 0000, nos quedaría tal que 0034. Lo mismo ocurre con los decimales, si tenemos nuevamente 34, el resultado de aplicar 0000.00 seria 0034.00.
  • ‘#’: La almohadilla (#), sirve para dar formato a los dígitos ignorando los ceros innecesarios. Por ejemplo, si tenemos el 0034 y el 0034.0500 y le aplicamos el formato #.#, nos dará como resultado 34 en primer lugar y 34.1 en segundo lugar. OJO, que redondea los números, si pusiéramos al 0034.0500 dos almohadillas tal que #.##, quedaría 34.05. Tener en cuenta, además de que redondea los números, que ignorara todos los ceros que haya después de la posición que ocuparía la almohadilla, a diferencia del ‘0’, que mantendría esos ceros.
  • ‘.’: El punto se utiliza para establecer el limitador decimal, para diferenciar entre la parte entera y la decimal.
  • ‘,’: La coma se utiliza para indicar si queremos y donde queremos situar los separadores de miles, por ejemplo, si tenemos 1000 y le aplicamos un formato tal que # o ####, el resultado siempre sera 1000, pero si aplicamos el formato #,### nos quedara 1,000, que manteniendo el formato y pasando 12350, quedaría 12,350 como resultado.
  • ‘%’: Devuelve el resultado en %, como pasa en otros programas como el Excel, cuando le aplicamos el %, nos multiplicara por 100 y mantendrá el símbolo de porcentaje al final, tal que 7 con formato #% quedaría 700% como resultado.
  • Espero que os sirva tanto a vosotros como a mi.

Reemplazar texto en transformada xslt

Trabajo desde hace años usando de una forma intensiva las transformadas xslt, y a pesar de que son fáciles de utilizar y se pueden hacer infinidad de cosas, llegando al caso de ser propiamente dicho, un lenguaje de programación, hay algo que siempre he echado en falta. A pesar de que xsl tiene funciones para el tratamiento de cadenas como substring, startwith, concat, etc. nunca he visto que tenga una función para reemplazar texto, algo que seria muy útil. Siempre que he tenido que hacer un reemplazo de texto lo he hecho de diferentes formas, a cual mas chapucera. Si tenia que sustituir una frase entera, llenaba el xsl de xsl:if o de xsl:choose con sus consecuentes xsl:when, pero si tenia que sustituir parte de una frase, ya la cosa se complicaba mas, usando casi siempre el nombre de espacio user, y definiendo una función en el lenguaje que utilizaba (en mi caso .net), pero esto tiene un problema, si por algún casual, quiero migrar a otro lenguaje (que no veo yo a mi jefe mucho por la labor), la transformada no me serviría fuera del entorno de .net.

Para solucionar este problema, decidí crear una función de xsl, mas que una función es un template, pero como a mi me gusta usar los templates como funciones con parámetros, también me gusta llamarlas funciones. Bueno, el caso es que he creado una función/template, que recibe 3 parámetros, y que vendría a ser mas o menos como el replace de php, pero con el funcionamiento del replace de javascript, porque de momento solo reemplaza de 1 en 1, digamos que no es un replace all. La función recibe 3 parámetros, uno con el texto a base, la cadena de donde queremos reemplazar el texto, otro parámetro con el texto que va a ser reemplazado, y otro parámetro con el texto a reemplazar. El código de la función seria el siguiente:



   
   
   
   
   
   

   
   
   
   





   
      
      
      
   

Espero que esta pequeña función para xsl, os sea tan útil como a mi. Por cierto, el ejemplo me lo saque de uno que monte en el curro, así que cada uno lo tendrá que modificar en base a sus necesidades. A ver si me lo curro un poco y modifico la función para que sea un replace all, en lugar de un replace one.

Scroll al inicio