Soporte Unicode

En JasperReports, trabajar con textos necesita algunas herramientas dedicadas para procesar tanto las representaciones de caracteres como las propiedades de formato del texto. Cualquier texto puede considerarse como una secuencia de caracteres con una estructura de representación particular. La apariencia del texto consiste en la configuración de diseño (y párrafo) y fuente. Pero aunque en la mayoría de los casos, el diseño del texto permanece invariable, la configuración de la fuente puede cambiar cuando se ejecuta el informe en diferentes configuraciones regionales.

Sabemos que los diferentes idiomas necesitan diferentes conjuntos de caracteres con respecto a la representación de caracteres específicos. Por tanto, trabajar con textos significa trabajar con fuentes. Sin embargo, una discusión detallada sobre cómo usar fuentes en JasperReports está disponible en el capítulo Fuentes de informes .

Una de las principales características del contenido del texto de un informe es la posibilidad de internacionalizarlo. Significa que podemos ejecutar el informe en diferentes entornos localizados, utilizando diferentes idiomas y otras configuraciones de localización sin ninguna modificación codificada. La codificación de caracteres es una característica importante cuando se pretende internacionalizar un informe.

Codificación de caracteres

Un carácter es la unidad más pequeña de escritura que transmite una información significativa. Es un concepto abstracto, un personaje no tiene apariencia visual. La "A latina mayúscula" es un carácter diferente de la "A latina minúscula" y de la "A cirílica mayúscula" y la "Alfa griega mayúscula".

Una representación visual de un personaje se conoce como glyph. Cierto conjunto de glifos se llamafont. La "A latina mayúscula", la "A cirílica mayúscula" y la "Alfa griega mayúscula" pueden tener glifos idénticos, pero son caracteres diferentes. Al mismo tiempo, los glifos de la "A latina mayúscula" pueden verse muy diferentes en Times New Roman, Gill Sans y Poetica chancery en cursiva, pero siguen representando el mismo carácter.

El conjunto de caracteres disponibles se denomina repertorio de caracteres . La ubicación (índice) de un carácter dado dentro de un repertorio se conoce como su posición de código o punto de código. El método de representar numéricamente un punto de código dentro de un repertorio dado se llamacharacter encoding.

Las codificaciones se expresan normalmente en términos de octetos. Un octeto es un grupo de ocho dígitos binarios, es decir, ocho unos y ceros. Un octeto puede expresar un rango numérico entre 0 y 255, o entre 0x00 y 0xFF, para usar la notación hexadecimal.

Unicode

Un Unicode es un repertorio de caracteres que contiene la mayoría de los caracteres utilizados en los idiomas del mundo. Puede acomodar millones de caracteres y ya contiene cientos de miles. Unicode se divide en "planos" de 64K caracteres. El único que se utiliza en la mayoría de las circunstancias es el primer plano, conocido como plano multilingüe básico o BMP.

UTF-8 es la codificación recomendada. Utiliza un número variable de octetos para representar diferentes caracteres.

En un archivo JRXML, el atributo de codificación se especifica en el encabezado. Se utiliza en el momento de la compilación del informe para decodificar el contenido XML. Por ejemplo, si el informe contiene solo palabras en francés y caracteres como ç, é, â, entonces la codificación ISO-8859-1 (también conocida como Latin-1) es suficiente:

<?xml version = "1.0" encoding = "ISO-8859-1"?>

Como se vio arriba, idealmente podemos elegir el ajuste de codificación al juego de caracteres mínimo, que puede representar correctamente todos los caracteres en el documento. Pero en el caso de documentos multilingües (es decir, documentos que contienen palabras escritas en varios idiomas), se debe elegir la codificación adaptada al juego de caracteres mínimo, capaz de representar correctamente todos los caracteres del documento, incluso si pertenecen a diferentes idiomas. Una de las codificaciones de caracteres capaces de manejar documentos multilingües es laUTF-8, utilizado como valor de codificación predeterminado por JasperReports.

Los textos generalmente se guardan en archivos de paquetes de recursos en lugar de dentro del documento durante la internacionalización. Por lo tanto, hay casos en los que el propio JRXML parece completamente compatible con ASCII, pero los informes generados en tiempo de ejecución contienen textos ilegibles con ASCII. Como resultado, para un cierto tipo de formatos de exportación de documentos (como CSV, HTML, XHTML, XML y texto) también se debe conocer la codificación del documento generado. Los diferentes idiomas son compatibles con diferentes codificaciones de caracteres. Entonces, cada vez, necesitamos ejecutar un informe en un entorno localizado. Además, tenemos que saber cuál es la codificación de caracteres más adecuada para el idioma del documento generado. En este caso, la propiedad de codificación definida en el archivo JRXML en sí podría no ser más útil.

Para resolver este tipo de problemas, podemos utilizar una propiedad de cliente de exportación conocida como net.sf.jasperreports.export.character.encoding . Esta propiedad personalizada de exportación es predeterminada en UTF-8 y está presente en JasperReports.

Este valor predeterminado se establece en el archivo default.jasperreports.properties . Para opciones más específicas en el momento de la exportación, el parámetro de exportación CHARACTER_ENCODING también está disponible.

Ejemplo

Para demostrar el uso de la compatibilidad con Unicode en Jasperreports, escribamos una nueva plantilla de informe (jasper_report_template.jrxml). Save it to C:\tools\jasperreports-5.0.1\testdirectorio. Aquí, mostraremos un texto en diferentes idiomas usando los caracteres Unicode (\ uXXXX). Cualquier carácter codificado con UTF-8 se puede representar utilizando solo su código hexadecimal de 4 dígitos. Por ejemplo, la letra griega Γ se puede escribir como \ u0393. Cuando se encuentra una notación de este tipo, el motor solicita la representación de caracteres adecuada en el conjunto de caracteres y solo se imprimirá ese carácter en particular. El contenido del JRXML es el siguiente:

<?xml version = "1.0" encoding = "UTF-8"?>

<jasperReport xmlns = "http://jasperreports.sourceforge.net/jasperreports"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://jasperreports.sourceforge.net/jasperreports
   http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
   name = "jasper_report_template" language = "groovy" pageWidth = "595"
   pageHeight = "842" columnWidth = "555" leftMargin = "20" rightMargin = "20"
   topMargin = "20" bottomMargin = "20">

   <parameter name = "GreekText" class = "java.lang.String" isForPrompting = "false">
      <defaultValueExpression><![CDATA["\u0394\u03B5\u03BD "+
         "\u03BA\u03B1\u03C4\u03B1\u03BB\u03B1\u03B2\u03B1\u03AF"+
         "\u03BD\u03C9 \u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"]]>
      </defaultValueExpression>
   </parameter>
   
   <parameter name = "CyrillicText" class = "java.lang.String" isForPrompting = "false">
      <defaultValueExpression><![CDATA["\u042F \u043D\u0435 "+
         "\u043C\u043E\u0433\u0443 \u043F\u043E\u043D\u044F\u0442\u044C "+
         "\u0433\u0440\u0435\u0447\u0435\u0441\u043A\u0438\u0439"]]>
      </defaultValueExpression>
   </parameter>

   <parameter name = "ArabicText" class = "java.lang.String" isForPrompting = "false">
      <defaultValueExpression><![CDATA["\u0627\u0646\u0646\u0649 \u0644\u0627 "+
         "\u0627\u0641\u0647\u0645 \u0627\u0644\u0644\u063A\u0629 "+
         "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"]]>
      </defaultValueExpression>
   </parameter>
   
   <parameter name = "HebrewText" class = "java.lang.String" isForPrompting = "false">
      <defaultValueExpression><![CDATA["\u05D0\u05E0\u05D9 \u05DC\u05D0 "+
         "\u05DE\u05D1\u05D9\u05DF \u05E2\u05D1\u05E8\u05D9\u05EA"]]>
      </defaultValueExpression>
   </parameter>
   
   <title>
      <band height = "782">
         
         <textField>
            <reportElement x = "0" y = "50" width = "200" height = "60"/>
            
            <textElement>
               <font fontName = "DejaVu Sans" size = "14"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{GreekText} + "\n" + $P{CyrillicText}]]>
            </textFieldExpression>
         </textField>
         
         <staticText>
            <reportElement x = "210" y = "50" width = "340" height = "60"/>
            <textElement/>
            
            <text>
               <![CDATA["GreekText and CyrillicText"]]>
            </text>
         </staticText>
         
         <textField>
            <reportElement x = "0" y = "120" width = "200" height = "60"/>
            
            <textElement>
               <font fontName = "DejaVu Sans" size = "14" isBold = "true"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{GreekText} + "\n" + $P{CyrillicText}]]>
            </textFieldExpression>
				
         </textField>
         
         <staticText>
            <reportElement x = "210" y = "120" width = "340" height = "60"/>
            <textElement/>
            <text><![CDATA["GreekText and CyrillicText"]]></text>
         </staticText>
         
         <textField>
            <reportElement x = "0" y = "190" width = "200" height = "60"/>
            
            <textElement>
               <font fontName = "DejaVu Sans" size = "14" isItalic = "true" 
                  isUnderline = "true"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{GreekText} + "\n" + $P{CyrillicText}]]>
            </textFieldExpression>
				
         </textField>
         
         <staticText>
            <reportElement x = "210" y = "190" width = "340" height = "60"/>
            <textElement/>
            <text><![CDATA["GreekText and CyrillicText"]]></text>
         </staticText>
         
         <textField>
            <reportElement x = "0" y = "260" width = "200" height = "60"/>
            
            <textElement>
               <font fontName = "DejaVu Sans" size = "14" isBold = "true" 
                  isItalic = "true" isUnderline = "true"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{GreekText} + "\n" + $P{CyrillicText}]]>
            </textFieldExpression>
				
         </textField>
         
         <staticText>
            <reportElement x = "210" y = "260" width = "340" height = "60"/>
            <textElement/>
            <text><![CDATA["GreekText and CyrillicText"]]></text>
         </staticText>

         <textField>
            <reportElement x = "0" y = "330" width = "200" height = "60"/>
            
            <textElement textAlignment = "Right">
               <font fontName="DejaVu Sans" size = "22"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{ArabicText}]]>
            </textFieldExpression>
				
         </textField>
         
         <textField>
            <reportElement x = "210" y = "330" width = "340" height = "60"/>
            
            <textElement textAlignment = "Right">
               <font fontName = "DejaVu Sans" size = "22"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{HebrewText}]]>
            </textFieldExpression>
				
         </textField>
      
      </band>
   </title>
	
</jasperReport>

En el archivo anterior, podemos ver la presencia de la codificación UTF-8. Además, los fragmentos de texto Unicode localizados se almacenan en los parámetros del documento.

El código java para completar y generar el informe es el siguiente. Guardemos este archivoJasperUnicodeReportFill.java al directorio C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint.

package com.tutorialspoint;

import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;

public class JasperUnicodeReportFill {
   public static void main(String[] args) {
      String sourceFileName ="C://tools/jasperreports-5.0.1/test/" + 
         "jasper_report_template.jasper";

      try {
         JasperFillManager.fillReportToFile(sourceFileName, null, 
            new JREmptyDataSource());
      } catch (JRException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

   }
}

Aquí usamos una instancia de JREmptyDataSource al llenar informes para simular una fuente de datos con un registro en ella, pero con todos los campos en este único registro siendo nulos .

La generación del informe

Compilaremos y ejecutaremos el archivo anterior utilizando nuestro proceso de compilación ANT habitual. El contenido del archivo build.xml (guardado en el directorio C: \ tools \ jasperreports-5.0.1 \ test) es el siguiente.

El archivo de importación, baseBuild.xml, se selecciona del capítulo Configuración del entorno y debe colocarse en el mismo directorio que build.xml.

<?xml version = "1.0" encoding = "UTF-8"?>
<project name = "JasperReportTest" default = "viewFillReport" basedir = ".">
   <import file = "baseBuild.xml" />
   
   <target name = "viewFillReport" depends = "compile,compilereportdesing,run"
      description = "Launches the report viewer to preview the report 
      stored in the .JRprint file.">
      
      <java classname = "net.sf.jasperreports.view.JasperViewer" fork = "true">
         <arg value = "-F${file.name}.JRprint" />
         <classpath refid = "classpath" />
      </java>
		
   </target>
   
   <target name = "compilereportdesing" description = "Compiles the JXML file and
      produces the .jasper file.">
      
      <taskdef name = "jrc" classname = "net.sf.jasperreports.ant.JRAntCompileTask">
         <classpath refid = "classpath" />
      </taskdef>
      
      <jrc destdir = ".">
         <src>
            <fileset dir = ".">
               <include name = "*.jrxml" />
            </fileset>
         </src>
         <classpath refid = "classpath" />
      </jrc>

   </target>
	
</project>

A continuación, abramos la ventana de la línea de comandos y vayamos al directorio donde se coloca build.xml. Finalmente, ejecute el comandoant -Dmain-class=com.tutorialspoint.JasperUnicodeReportFill (viewFullReport es el destino predeterminado) de la siguiente manera:

C:\tools\jasperreports-5.0.1\test>ant  -Dmain-class=com.tutorialspoint.JasperUnicodeReportFill
Buildfile: C:\tools\jasperreports-5.0.1\test\build.xml

clean-sample:
   [delete] Deleting directory C:\tools\jasperreports-5.0.1\test\classes
   [delete] Deleting: C:\tools\jasperreports-5.0.1\test\jasper_report_template.jasper
   [delete] Deleting: C:\tools\jasperreports-5.0.1\test\jasper_report_template.jrprint

compile:
   [mkdir] Created dir: C:\tools\jasperreports-5.0.1\test\classes
   [javac] C:\tools\jasperreports-5.0.1\test\baseBuild.xml:28:
   warning: 'includeantruntime' was not set, defaulting t
   [javac] Compiling 1 source file to C:\tools\jasperreports-5.0.1\test\classes

compilereportdesing:
   [jrc] Compiling 1 report design files.
   [jrc] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory).
   [jrc] log4j:WARN Please initialize the log4j system properly.
   [jrc] log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
   [jrc] File : C:\tools\jasperreports-5.0.1\test\jasper_report_template.jrxml ... OK.

run:
   [echo] Runnin class : com.tutorialspoint.JasperUnicodeReportFill
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.extensions.ExtensionsEnvironment).
   [java] log4j:WARN Please initialize the log4j system properly.

viewFillReport:
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.extensions.ExtensionsEnvironment).
   [java] log4j:WARN Please initialize the log4j system properly.

BUILD SUCCESSFUL
Total time: 4 minutes 1 second

Como resultado de la compilación anterior, se abre una ventana de JasperViewer como se muestra en la pantalla que se muestra a continuación:

Aquí, podemos ver que el texto que se muestra está en diferentes idiomas. También vemos que los idiomas están agrupados en la misma página y también mezclados en el mismo elemento de texto.