Voir ma mise à jour en bas pour en savoir plus.
J'ai parfois des projets où je dois sortir des données sous forme de fichier Excel (format xlsx). Le processus est généralement:
L'utilisateur clique sur certains boutons de mon application
Mon code exécute une requête DB et traite les résultats d'une manière ou d'une autre
Mon code génère un fichier * .xlsx à l'aide des bibliothèques d'interopérabilité Excel com ou d'une bibliothèque tierce (par exemple, Aspose.Cells)
Je peux facilement trouver des exemples de code sur la façon de le faire en ligne, mais je cherche un moyen plus robuste de le faire. J'aimerais que mon code suive certains principes de conception pour garantir que mon code soit maintenable et facilement compréhensible.
Voici à quoi ressemblait ma tentative initiale de générer un fichier xlsx:
var wb = new Workbook();
var ws = wb.Worksheets[0];
ws.Cells[0, 0].Value = "Header";
ws.Cells[1, 0].Value = "Row 1";
ws.Cells[2, 0].Value = "Row 2";
ws.Cells[3, 0].Value = "Row 3";
wb.Save(path);
Avantages: Pas grand-chose. Cela fonctionne, donc c'est bien.
Les inconvénients:
- Les références de cellule sont codées en dur, j'ai donc des nombres magiques éparpillés dans mon code.
- Il est difficile d'ajouter ou de supprimer des colonnes et des lignes sans mettre à jour de nombreuses références de cellule.
- J'ai besoin d'apprendre une bibliothèque tierce. Certaines bibliothèques sont utilisées comme d'autres bibliothèques, mais il peut toujours y avoir des problèmes. J'ai eu un problème où les bibliothèques COM Interop utilisent le référencement de cellule basé sur 1 alors que Aspose.Cells utilise le référencement de cellule basé sur 0.
Voici une solution qui résout certains des inconvénients que j'ai énumérés ci-dessus. Je voulais traiter une table de données comme son propre objet qui peut être déplacé et modifié sans creuser dans la manipulation des cellules et perturber les autres références de cellules. Voici un pseudocode:
var headers = new Block(new string[] { "Col 1", "Col 2", "Col 3" });
var body = new Block(new string[,]
{
{ "Row 1", "Row 1", "Row 1" },
{ "Row 2", "Row 2", "Row 2" },
{ "Row 3", "Row 3", "Row 3" }
});
body.PutBelow(headers);
Dans le cadre de cette solution, j'aurai un objet BlockEngine qui prend un conteneur de blocs et effectue les manipulations de cellule requises pour sortir les données sous forme de fichier * .xlsx. Un formatage peut être associé à un objet Block.
Avantages:
- Cela supprime la plupart des nombres magiques que possédait mon code initial.
- Cela cache beaucoup de code de manipulation de cellules, bien que la manipulation de cellules soit toujours requise dans l'objet BlockEngine que j'ai mentionné.
- Il est beaucoup plus facile d'ajouter et de supprimer des lignes sans affecter les autres parties de la feuille de calcul.
Les inconvénients:
- Il est toujours difficile d'ajouter ou de supprimer des colonnes. Si je voulais échanger la position des colonnes deux et trois, je devrais échanger directement le contenu des cellules. Dans ce cas, ce serait huit modifications, et donc huit occasions de faire une erreur.
- Si j'ai un formatage en place pour ces deux colonnes, je dois également le mettre à jour.
- Cette solution ne prend pas en charge le placement de bloc horizontal; Je ne peux placer qu'un bloc en dessous d'un autre. Bien sûr, j'aurais pu
tableRight.PutToRightOf(tableLeft)
, mais cela causerait des problèmes si tableRight et tableLeft avaient un nombre différent de lignes. Pour placer des tables, le moteur doit être conscient de toutes les autres tables. Cela me semble inutilement compliqué. - J'ai encore besoin d'apprendre le code tiers, bien qu'à travers une couche d'abstraction via des objets Block et un BlockEngine, le code sera moins étroitement couplé à la bibliothèque tierce que ma tentative initiale. Si je voulais prendre en charge de nombreuses options de formatage de manière lâche, je devrais probablement écrire beaucoup de code; mon BlockEngine serait un énorme gâchis.
Voici une solution qui prend un itinéraire différent. Voici le processus:
Je prends mes données de rapport et génère un fichier xml dans un format que je choisis.
J'utilise ensuite une transformation xsl pour convertir le fichier xml en un fichier de feuille de calcul XML Excel 2003.
De là, je convertis simplement la feuille de calcul xml en un fichier xlsx à l'aide d'une bibliothèque tierce.
J'ai trouvé cette page qui décrit un processus similaire et inclut des exemples de code.
Avantages:
- Cette solution ne nécessite presque aucune manipulation cellulaire. Vous utilisez plutôt xsl / xpath pour effectuer vos manipulations. Afin d'échanger deux colonnes dans un tableau, vous déplacez toutes les colonnes du fichier xsl contrairement à mes autres solutions qui nécessiteraient un échange de cellule.
- Bien que vous ayez toujours besoin d'une bibliothèque tierce qui peut convertir une feuille de calcul XML Excel 2003 en un fichier xlsx, c'est à peu près tout ce dont vous aurez besoin pour la bibliothèque. La quantité de code dont vous avez besoin pour écrire et qui serait appelée dans la bibliothèque tierce est minuscule.
- Je pense que cette solution est la plus facile à comprendre et nécessite le moins de code.
- Le code qui crée les données dans mon propre format xml sera simple.
- Le fichier xsl sera compliqué uniquement parce que la feuille de calcul XML Excel 2003 est compliquée. Cependant, il est facile de vérifier la sortie du fichier xsl: ouvrez simplement la sortie dans Excel et recherchez les messages d'erreur.
- Il est facile de générer des exemples de fichiers de feuille de calcul XML Excel 2003: il suffit de créer une feuille de calcul qui ressemble à votre fichier xlsx souhaité, puis de l'enregistrer en tant que feuille de calcul XML Excel 2003.
Les inconvénients:
- Les feuilles de calcul XML Excel 2003 ne prennent pas en charge certaines fonctionnalités. Vous ne pouvez pas ajuster automatiquement la largeur des colonnes par exemple. Vous ne pouvez pas inclure d'images dans les en-têtes ou les pieds de page. Si vous allez exporter le fichier xlsx résultant au format pdf, vous ne pouvez pas définir de signets pdf. (J'ai piraté un correctif pour cela en utilisant les commentaires des cellules.). Vous devez le faire en utilisant votre bibliothèque tierce.
- Nécessite une bibliothèque qui prend en charge les feuilles de calcul XML Excel 2003.
- Utilise un format de fichier MS Office vieux de 11 ans.
Remarque: je me rends compte que les fichiers xlsx sont en fait des fichiers zip contenant des fichiers xml, mais le formatage xml semble trop compliqué pour mes besoins.
Enfin, j'ai cherché des solutions impliquant SSRS, mais cela semble trop gonflé pour mes besoins.
Revenons à ma question initiale, quel est un bon modèle de conception pour générer des fichiers Excel en code?. Je peux penser à quelques solutions, mais aucune ne semble idéale. Chacun a ses inconvénients.
Mise à jour: J'ai donc essayé à la fois ma solution BlockEngine et ma solution de feuille de calcul XML pour générer des fichiers XLSX similaires. Voici mes opinions à leur sujet:
La solution BlockEngine:
- Cela nécessite simplement trop de code compte tenu des alternatives.
- J'ai trouvé trop facile d'écraser un bloc avec un autre si j'avais un mauvais décalage.
- J'ai initialement indiqué que le formatage pouvait être attaché au niveau du bloc. J'ai trouvé que ce n'était pas beaucoup mieux que de faire le formatage séparément du contenu du bloc. Je ne vois pas de bonne façon de combiner le contenu et la mise en forme. Je ne peux pas non plus trouver un bon moyen de les séparer. C'est juste un gâchis.
La solution de feuille de calcul XML:
- Je vais avec cette solution pour l'instant.
- Il convient de répéter que cette solution nécessite beaucoup moins de code. Je remplace efficacement le BlockEngine par Excel lui-même. J'ai toujours besoin d'un hack pour des fonctionnalités telles que les signets et les sauts de page.
- Le format de feuille de calcul XML est capricieux, mais il est facile d'apporter une petite modification et de comparer les résultats à un fichier existant dans votre programme Diff préféré. Et une fois que vous avez compris une idiosyncrasie, vous pouvez la mettre en place et l'oublier à partir de là.
- Je suis toujours préoccupé par le fait que cette solution repose sur un ancien format de fichier Excel.
- Le fichier XSLT que j'ai créé est facile à utiliser. La gestion du formatage est beaucoup plus simple ici qu'avec la solution BlockEngine.