Exportando desde WXTABLE con HTML+CSS a XLSX

Figura
Figura. Exportar a XLSX en WXTABLE

Cuando hice el Gestor de tablas WXTABLE incluí varios formatos de exportación a falta del formato XLSX. Ahora se incluye este nuevo formato tras estudiar previamente un par de cosas necesarias para llevarlo a cabo. Una de ellas es saber cómo crear un ZIP, puesto que un XLSX es en esencia un ZIP con los datos en archivos XML empaquetados en un archivo ZIP.

Pero para saber cómo funciona un ZIP es necesario antes saber cómo generar un CRC. En esa serie de temas se explica a fondo qué es el CRC y en el último tema se plantea una implementación práctica de CRC-32/ISO-HDLC que nos servirá de base al crear un ZIP para empaquetar los XML de un XLSX.

El gestor de tablas WXTABLE se inicia con 10 columnas y 10 filas. Se gestionan con el elemento HTML <table>. Su utilidad principal es crear tablas de una forma parecida a como lo hace Excel o GoogleSheet, pero con la finalidad de exportarlas a HTML con mayor facilidad. Y al mismo tiempo poder usar todos los recursos de HTML y CSS, con lo que se integran mejor y con menos recursos en una página web.

Figura
Figura. Aplicación Gestor tablas WXTABLE

En la Figura se observa una vista del Gestor de tablas. Contiene los recursos necesarios para crear una tabla HTML con estilos CSS para las celdas: color, fondos incluso imágenes, bordes, rellenos, alineaciones, fuentes, decoraciones de texto, etc. Se pueden aplicar también estilos CSS a las filas, columnas y la propia tabla. Es posible introducir HTML dentro de las celdas con algunas limitaciones, pero que nos permite emular el texto enriquecido. Se utilizan fórmulas que se ejecutan con el módulo calc.js. Permite combinar celdas, ocultar filas y columnas, aplicar formatos de número, moneda y fecha, insertar controles de verificación, radio, lista y botones, insertar gráficas con SVG y algunas cosas más.

En resumen, una aplicación que genera una tabla con posibilidades similares a las básicas que ofrecen las hojas de cálculo. Pero en ningún caso es un sustituto, pues la finalidad como dije antes es generar tablas HTML para insertar en una página web. Como hay muchas cosas similares es por lo que intento exportar una WXTABLE en un XLSX.

El módulo exportador XLSX

El módulo xlsx.js es el que se encarga de realizar la exportación desde WXTABLE a XLSX. Cuando se carga ese módulo tendremos disponible el objeto {version, configIni, build, create, zippit, download}. En una ejecución trazamos en la consola del navegador su contenido:

version: "21-07-2021"
configIni: {colWidth: 72, minWidthCol: 24, fontSize: 12, fontName: "Arial", …}
build: ƒ build({sheets=null, images=[], config=null}={})
create: ƒ create({source=null, runZip=null, lang="en"}={})
zippit: ƒ zippit({built=null, runZip=null, lang="en"}={})
download: ƒ download({arrayBytes=null, filename="spreadsheet.xlsx", lang="en"}={})

En configIni tenemos la configuración del exportador que explicaremos más adelante. Aparte de esta configuración y de la versión del módulo, el resto son funciones que ejecutan la exportación.

Se puede ejecutar build({sheets, images, config}) y obtener el objeto built con los archivos XML, para luego usar zippit({built, runZip, lang}) y obtener el buffer o arrayBytes del ZIP. O bien usar create({source, runZip, lang}) donde source = {sheets, images, config}, ejecutándose build() y zippit() obteniéndose el buffer ZIP. El argumento runZip es una referencia al módulo que ejecuta el ZIP. En cualquier caso luego descargaremos con download({arrayBytes, filename, lang}).

Observe que el objeto source es de la forma {sheets=null, images=[], config=null}. Los argumentos sheets e images tienen la estructura que se exporta en el formato wxtable desde el Gestor de tablas. Sin embargo el argumento config no es el del Gestor de tablas. Por ejemplo, si exportamos una tabla inicial vacía tendremos este JSON en formato wxtable, donde hemos omitido el contenido de la propiedad config. Puede verlo completo en este archivo de texto wxtable-export-empty.txt).

{
    "caption":"",
    "config":{...},
    "sheets":
        {
            "Tab1":{
                "index":0,
                "attributes":{},
                "styles":{},
                "values":[
                    ["1","2","3","4","5","6","7","8","9","10"],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""],
                    ["","","","","","","","","",""]
                ]
            }
        },
    "images":[]
}

Para usar ese objeto como source de las funciones del módulo xlsx.js hemos de eliminar la entrada config o bien sustituirla por la propia configuración del exportador. Mantenemos sheets e images, mientras que otras propiedades como caption e index serán ignoradas.

La configuración que usa el exportador XLSX tiene otras estructura y valores iniciales que veremos más abajo. Podemos pasar ese objeto que explicaremos en ese apartado, o bien ninguno, o bien sólo aquellas propiedades que difieran de su valor inicial.

Herramienta Web Tools online para exportar a XLSX

Figura
Figura. Web Tools online para exportar a XLSX

Aparte de descargar directamente desde el Gestor de tablas a un archivo XLSX, también podemos usar la herramienta Exportador XLSX, que nos permitirá trazar el proceso de exportación. También puede consultar la página Información exportador XLSX de esa herramienta.

Vamos a resumir lo que vemos en la Figura, una captura de esa herramienta.

En el área de texto Objeto WXTABLE incluiremos el JSON de la tabla que exportamos desde el Gestor de tablas. Se puede editar directamente si se quisiera. También es posible elegir una muestra desde una lista para Iniciar datos, rellenándose esa área de texto con la muestra.

Hay un panel que despliega unas Opciones para la ejecución del exportador y que explicaremos en un apartado más abajo.

El siguiente paso es Construir el XLSX, rellenándose una lista de archivos XML que componen el conjunto de archivos XLSX. Seleccionando un archivo podemos ver su contenido resaltado.

Luego pasamos a Crear el XLSX generándose el ZIP que empaqueta los archivos XML, vertiéndose el contenido del buffer ZIP en otra área de texto. Estos son los bytes del ZIP que se muestran sólo a título informativo, sin posibilidad de edición.

Por último podemos Descargar el ZIP que se nombra con la extenxión "xlsx" y que es el archivo XLSX generado y descargado.

Configuración del exportador XLSX

La configuración inicial del exportador XLSX es la siguiente:

const configIni = {
    colWidth: 72,
    minWidthCol: 24,
    rowHeight: 15,
    fontSize: 12,
    fontName: "Arial",
    fontFamily: 2,
    dataExtend: 1,
    maxRow: 0, //Máxima fila
    maxCol: 0, //Máxima columna
    checkView: "list", //Vista check box
    radioView: "list", //Vista radio
    lang: "es", //Idioma mensajes
    rn: "\n", //Salto de línea
    tab: 4 //Tabulación
};

Podemos pasar este objeto dentro del objeto source en las funciones que ejecutan la exportación, como vimos más arriba. Pero realmente sólo son editables las últimas propiedades que tiene un comentario.

Figura
Figura. Configuración del exportador XLSX

Tal como se observa en la Figura, sólo se permite modificar maxRow y maxCol que fijan la máxima fila y columna; checkView y radioView que fijan las vistas de los controles check y radio; lang que fija el idioma inglés o español a usar en la interfaz del exportador; rn que fija el salto de línea; tab que fija la tabulación o sangría que se usarán en el código de los documentos XML.

El resto son propiedades que fijan el comportamiento inicial en el Gestor de tablas WXTABLE. No se deberían en principio modificar puesto que entonces no reflejarían adecuadamente el comportamiento de WXTABLE y, por otro lado, los valores diferentes de los iniciales serán ignorados en el exportador XLSX.

El problema por ahora que no he afrontado es que esas propiedades que configuran el comportamiento inicial en WXTABLE no son configurables. Por ejemplo colWidth establece el ancho de columna inicial a 72pt que equivale a 96px en WXTABLE. Podemos cambiar los anchos de las columnas en WXTABLE, pero no el valor inicial. Lo mismo pasa con fontName para la fuente "Arial" y tamaño 12pt (16px, 1em) iniciales. Con rowHeight se configura la altura de fila inicial, con 15pt (20px), usando la altura de línea o line-height de CSS con valor "normal", que equivale al valor 1.25, resultando entonces el cálculo rowHeight = fontSize × lineHeight = 12pt × 1.25 = 15pt.

La propiedad minWidthCol establece el ancho mínimo de una columna, que en WXTABLE es de 24pt (36px), con objeto de que siempre pueda mostrarse un mínimo para poder interaccionar con el selector de columna.

Y por último, el atributo dataExtend que inicialmente tiene valor verdadero, con objeto de que XLSX refleje que el texto no se salga de la celda y se comporte por defecto como lo hace en una tabla HTML y, por tanto, en las tablas WXTABLE. La posibilidad de editar alguna o todas estas propiedades podría cambiar en el futuro, pero por ahora funcionará así.

Documentación de Office Open XML

Figura
Figura. ECMA 376 Office Open XML-Part 1

Office Open XML es un formato abierto para representar y almacenar documentos de texto (.docx), hojas de cálculo (.xlsx) y presentaciones (.pptx). Cuando se afronta la implementación particular de una tecnología lo primero que hacemos es buscar documentación al respecto. Wikipedia Office Open XML nos empieza dando un resumen sobre el tema. Vemos que hay dos estándares: ECMA-376 e ISO/IEC-29500. Usaré el primero de los anteriores.

En la página ECMA-376 Office Open XML file formats, 5th edition, December 2016, se obtiene el último estándar publicado. En la parte primera hay un PDF de unos 28MB como se observa en la Figura, se incluyen los elementos de Office Open Wordprocessing, Spreadsheet y Presentation. Sólo nos interesa la parte de hojas de cálculo (Spreadsheet). En adelante nos referiremos a este documento como OOX.