Autoblog du Hollandais Volant

Ce site n'est pas le site officiel lehollandaisvolant.net.
C'est un blog automatisé qui réplique les articles de lehollandaisvolant.net

Produire un fichier Excel en JS

Thu, 14 Dec 2023 18:55:03 +0100 - (source)

Code excel.
… et en moins de 10 lignes de code.

Mon problème était de rendre simple l’export de données stockés dans un outil web (SQL + PHP + JS) en fichier Excel.
Au départ, j’avais proposé une production de code CSV, que l’utilisateur devait copier-coller dans Excel, puis fait quelques manips pour qu’Excel ne voie pas une plâtrée de texte, mais du CSV (chose que LibreOffice fait tout seul).

Mais c’était trop compliqué.

Le mieux que j’ai trouvé ensuite, c’est de produire un tableau dans la page web, en HTML, puis sélectionner le contenu, le copier, et prier pour qu’Excel détecte ça comme un tableau et redistribue ça dans les bonnes cellules.

Mais c’était ni assez simple, ni suffisamment fiable.

Du coup j’ai pondu un système avec un bouton : on clique dessus et ça ouvre Excel (.xls) directement avec le contenu du tableau.

Bien plus simple.

Prérequis

Le tableau de données doit être produit en tant que tableau HTML. Le tableau n’a pas besoin d’être dans la page. Cela peut être un objet DOM quelque part.
L’astuce ici fonctionne donc que le tableau soit dans la page, en mémoire, ou bien produit à la volée à partir des données brutes au moment du clic.

Le fait de l’afficher dans la page permet cependant de montrer le tableau avant de le proposer au téléchargement.

Fonctionnement

Un fichier Excel reste du simple XML. Il suffit de prendre les entêtes d’un fichier .xls et de mettre le tableau HTML en dessous. Ensuite, on récupère tout ça sous forme de base64, on force le navigateur à télécharger ça.

Code

Le HTML


<button type="button" onclick="tableToExcel(ID_TABLEAU)">Export to Excel</button>

<table id="ID_TABLEAU">
    …
    …
</table>

Le JS :


function tableToExcel(table_ID) {
	var template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>Worksheet</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>';
	var table = document.getElementById(table_ID).innerHTML;
	var xml_table = template.replace(/{table}/g, table);
	var base64_xml_table = window.btoa(unescape(encodeURIComponent(xml_table)));
	window.location.href = 'data:application/vnd.ms-excel;base64,' + base64_xml_table;
}

Je n’ai pas dit que c’était propre, mais ça marche.

Petite amélioration

Ici, le nom du fichier est plus ou moins une chaîne aléatoire. On peut changer ça, en utilisant un lien plutôt qu’un bouton : le bouton modifie l’URL de la page, mais avec un lien on peut actionner le téléchargement directement, avec l’attribut download.

Et si on veut juste garder l’apparence du bouton, on peut simplement mettre le lien autour du bouton :

<a href="#" download="tableau.xls"  onclick="tableToExcel(this, 'ID_TABLEAU')"><button>Export to Excel</button></a>

<table id="ID_TABLEAU">
    …
    …
</table>
function tableToExcel(link, table_ID) {
	var template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>Worksheet</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>';
	var table = document.getElementById(table_ID).innerHTML;
	var xml_table = template.replace(/{table}/g, table);
	var base64_xml_table = window.btoa(unescape(encodeURIComponent(xml_table)));
	link.href = 'data:application/vnd.ms-excel;base64,' + base64_xml_table;
}

Exemples

Exemple sur Codepen.io.

Notes et limites

Une des limites est que les styles ne sont pas forcément pris en compte. Les dispositions des cellules (rowspan et colspan) semblent bien fonctionner systématiquement, du moment que le tableau est en HTML et pas reconstitué avec du CSS (display: table-cell, ou encore avec des grid), mais les couleurs et autres formatages ne sont pas garanties.

Un autre problème peut survenir quand les tableaux sont vraiment très grands. Je ne sais pas si les navigateurs mettent une limite sur le contenu d’un href, mais ce n’est pas exclu non plus.

Image d’en-tête produite par Bing AI


Powered by VroumVroumBlog 0.1.31 - RSS Feed
Download config articles