Étiquette : Excel

Vincent Lecomte
[Java] Jsoup HTML Parser

[Java] Jsoup HTML Parser

Il arrive parfois que l’on retrouve des fichiers dans un format Excel qui ne le sont pas vraiment. En y regardant de plus près et même si l’extension est “xls“, on peut tomber nez-à-nez avec un fichier HTML qui contient un tableau. Dans notre cas il a fallu transformer le fichier suivant en un fichier CSV (séparateur “;”). Avec Jsoup, c’est beaucoup plus facile à réaliser ! Il va “parser” le contenu du fichier donné en paramètre… il ne reste plus qu’à manipuler et traiter les différents éléments.

<html xmlns:x="urn:schemas-microsoft-com:office:excel"> 
<table border="1" columns="3"> 
 <tr> 
  <th>Header1</th> 
  <th>Header2</th> 
  <th>Header3</th> 
 </tr> 
 <tr> 
  <td>LaDonnee1</th> 
  <td>LaDonnee2</th> 
  <td>LaDonnee3</th> 
 </tr> 
</table> 
</html>

Ensuite nous allons simplement utiliser l’API Jsoup pour manipuler les différents éléments afin de tout mettre dans un fichier CSV (encodage ANSI). Ici chaque ligne du tableau en HTML va être copiée dans le CSV avec, entre chaque “colonne”, le séparateur “;”. Une ligne dans le fichier texte = une ligne du tableau HTML.

File input = new File(args[0]); 
File outpt = new File(args[1]); 
Document doc = Jsoup.parse(input, "UTF-8"); 
Elements tbl = doc.select("tr"); 
try (FileOutputStream fos = new FileOutputStream(outpt); 
	BufferedWriter bw = new BufferedWriter( 
		new OutputStreamWriter(fos,"UTF-8"))) 
{ 
	for (Element trb : tbl) 
	{ 
		Elements td = trb.children(); 
		i = 1; 
		for (Element tdb : td) 
		{ 
			if (i==1) 
			{ 
				bw.write(tdb.text()); 
			}
			else 
			{ 
				bw.write(";"+tdb.text()); 
			} 
			
			i++; 
		} 
		
		bw.newLine(); 
	} 
}

En résumé, voici ce qu’on a réalisé :

  • Parsing du document avec la fonction Jsoup.Parse(). Les paramètres sont le fichier source et le jeu d’encodage (charset). Elle renverra une exception si le fichier n’a pas pu être chargé.
  • Sélection de tous les éléments “tr” avec la méthode Document.select(). Celle-ci doit être appelée directement par l’instance qui a été créée ci-dessus.
  • On va créer un flux de sortie pour le fichier destination (FileOutputStream) et l’objet qui va nous permettre d’y écrire (BufferedWriter). On en profite pour déterminer le jeu d’encodage de caractères.
  • On parcourt l’ensemble des lignes à l’aide de l’instruction “for”.
  • On récupère les éléments “enfants”.
  • Parmi ces éléments on va considérer qu’il s’agit des lignes. Il faut vérifier plus attentivement mais il semblerait que la méthode “children()” renvoie les éléments qui devraient logiquement apparaitre selon les spécifications de la syntaxe. En effet, durant mes tests, j’ai vu l’élément “tbody” apparaitre, or il n’existe pas dans mon fichier source.
  • Parcourir l’ensemble des cellules (instruction “for”).
  • Écriture des données des cellules à l’aide de la fonction bw.write().
  • On rajoute une nouvelle ligne dans notre CSV avant le prochain tour de boucle à l’aide de la méthode bw.newLine().
  • Les ressources sont automatiquement libérées avec cette syntaxe de “try” Rien n’empêche d’écrire tout ça à l’ancienne!

Et voilà… bien sûr, cela reste très basique et ce code pourrait être amélioré afin de répondre à d’autres cas plus spécifiques. Bon développement et bonne découverte à tous.

[WD20] Remplir plusieurs cellules Excel par OLE

[WD20] Remplir plusieurs cellules Excel par OLE

Cette technique permet de gagner en performances lorsqu’on cherche à piloter Excel à l’aide d’OLE Automation. En effet, si par exemple on cherche à alimenter les cellules A1 à B5 (soit 10 cellules, sur deux colonnes distinctes), on va pouvoir utiliser un tableau de variants à 2 dimensions. La solution a été proposée sur les forums de PC SOFT par Jurassic Pork.

Si vous ne vous souvenez plus de la manière dont il faut déclarer les différentes variables afin de piloter Excel, vous pouvez consulter l’article “Pilotage Excel via OLE” sur le blog. Dans notre exemple nous allons déclarer des objets supplémentaires qui représenteront respectivement une feuille spécifique et une plage de cellules.

MaFeuille est un objet automation dynamique
MaPlage est un objet automation dynamique
MonTableauAutomation est un tableau de 5 par 2 Variant

MaFeuille = objXLApp>>Worksheets("Feuil1")
POUR i = 1 A 5
  MonTableauAutomation[i,1]="Donnée_A_" + i
  MonTableauAutomation[i,2]="Donnée_B_" + i
FIN

MaPlage = MaFeuille>>Range("A1:B5")
MaPlage>>Value = MonTableauAutomation

Dans le code ci-dessus on a volontairement supprimé l’ouverture du classeur et le test pour vérifier s’il a bien été chargé. La déclaration de l’objet “objXLApp” n’est d’ailleurs pas présente ici.

Bon développement à tous.

[Office] Bulletin MS14-082 et problème d’ActiveX

[Office] Bulletin MS14-082 et problème d’ActiveX

Suite à la mise à jour corrective MS14-082 pour les suites Office, de nombreux utilisateurs ont vite constaté un problème avec leurs contrôles ActiveX, notamment dans un classeur Excel. Il s’agit des mises à jour de sécurité suivantes, destinées à colmater une faille qui permettait l’exécution de code distant :

  • Security Update for Microsoft Office 2007 (KB2596927).
  • Security Update for Microsoft Office 2010 (KB2553154).
  • Security Update for Microsoft Office 2013 (KB2726958).

Les symptômes rencontrés peuvent varier d’une machine à une autre. On note les problèmes suivants :

  • Contrôles ActiveX inactifs / impossibilité de modifier leurs propriétés.
  • Erreur indiquant “Impossible d’insérer un objet” (Cannot insert object).
  • Erreur indiquant “Le programme utilisé pour créer cet objet est xxxx. Ce programme n’est pas installé sur votre ordinateur ou ne répond pas (…)“.
  • Erreur 438, “L’objet ne gère pas cette propriété ou méthode” en tentant de pointer vers un contrôle ActiveX depuis le code (d’un classeur).
  • Problème affectant le nom d’un contrôle donné lors de sa création.

Plusieurs solutions s’offrent à vous, certaines peuvent ne pas fonctionner selon la version Office utilisée sur votre machine.

Désinstaller la mise à jour

La première solution qui nous vient à l’esprit est de désinstaller la mise à jour de votre système (voir ci-dessous pour repérer le correctif correspondant). Sur Windows 7 et Windows 8, rendez-vous dans le Panneau de configuration, Windows Update, Mises à jour installées, sélectionnez la mise à jour puis cliquez sur Désinstaller. Cependant cela ne sera peut-être pas forcément nécessaire : la solution suivante consiste à nettoyer les fichiers temporaires, et nous allons voir pourquoi !

Nettoyer les fichiers temporaires

En consultant les différents blogs, dont celui de Microsoft, la solution proposée est toujours la même. Celle-ci consiste à nettoyer les fichiers temporaires qui servent de cache. Trois méthodes sont disponibles : manuelle, scriptée ou automatisée. A vous de choisir celle que vous préférez, en fonction de votre niveau de compétences.

1 – Méthode manuelle

Après la mise à jour, les libraires de types de contrôles, mises en cache, sont “désynchronisées”. Elles sont stockées sous le format “Extender files” (*.exd). Il faut alors supprimer ces fichiers à plusieurs endroits de votre disque.

  • %appdata%\microsoft\forms
  • %temp%\excel8.0
  • %temp%\word8.0
  • %temp%\PPT11.0
  • %temp%\vbe

Vous pouvez également chercher après le fichier “MSForms.exd” dans %TEMP% et %APPDATA%. Attention, n’oubliez pas de fermer les applications Microsoft Office (Excel, PowerPoint, etc) avant d’effectuer cette opération. Un redémarrage peut être nécessaire par la suite.

2 – Utilisation d’un script

Étant donné que le problème peut affecter plusieurs machines il peut être intéressant de concevoir un script batch qui contiendra les lignes suivantes :

del %temp%\vbe*.exd
del %temp%\excel8.0*.exd
del %appdata%\microsoft\forms*.exd
del %appdata%\microsoft\local*.exd
del %temp%\word8.0*.exd
del %temp%\PPT11.0*.exd

Enregistrez le fichier en lui donnant l’extension “.bat”. Lancez-le pour chaque profil car les fichiers “.exd” sont spécifiques à l’utilisateur. Pour automatiser ce script lors de l’identification dans un domaine, vous pouvez suivre le tutoriel suivant : Setting up a Logon Script through Active Directory Users & Computers (en).

3 – Méthode automatisée

Microsoft a mis en ligne un script qui permet d’effectuer ces opérations. Il peut être obtenu à l’adresse suivante : “Cannot insert object Error in an ActiveX custom Office solution after you install the MS14-082 security updatehttps://support.microsoft.com/kb/3025036/EN-US.

Notes

%TEMP% correspond habituellement à : C:\Users\NOM\AppData\Local\Temp.
%APPDATA% correspond habituellement à : C:\Users\NOM\AppData\Roaming.

Sources

BornCity
ExcelMatters
Microsoft Blog

[WD19] Pilotage Excel via OLE

[WD19] Pilotage Excel via OLE

Depuis votre application Windev, il est possible de piloter des applications Windows via le protocole OLE (“Object Linking and Embedding”). Par exemple vous pouvez créer une feuille Excel formatée avec un ensemble de données reprises dans un tableau : colorez telles cellules en rouge, modifiez la mise en page, modifiez le zoom actif, changez l’orientation de l’impression, etc.

Tout d’abord, il faut définir la variable qui va permettre l’interaction avec le processus Excel et l’appel des différentes méthodes pour mettre en forme notre futur document. Cette variable est de type “Objet OLE dynamique”. On va l’initialiser d’abord avec la valeur retournée par la fonction ObjetActif(), puis déterminer l’action à effectuer en fonction du retour.

Ce qui est réalisé ci-dessus :

  • On définit la variable de type “Objet OLE dynamique”.
  • On l’initialise avec la fonction ObjetActif, à laquelle on passe en paramètre le nom du serveur automation, à savoir “Excel.Application”.
  • Dans l’instruction “Selon”, on va vérifier si le résultat est à Null : si c’est le cas, cela veut dire qu’il n’y a aucun fichier Excel actif, et on peut allouer un nouvel objet de type “Excel.Application”. Dans les autres cas, cela signifie qu’il y a un fichier en cours d’édition. On va alors appeler la méthode “Quit()” de l’objet, en utilisant l’opérateur “>>” (exemple : “monFichierXls>>Quit()”), détruire l’objet, puis réaliser une nouvelle allocation.

Note : les objets Automation sont automatiquement détruits à la fin du traitement, cependant, si vous souhaitez libérer des objets plus tôt, utilisez le mot-clé “libérer” (exemple : “libérer monFichierXls”).

Lorsqu’on a réalisé cette opération, on peut alors commencer la création et l’édition d’une feuille dans le nouveau document, et même la renommer. Tout d’abord, on va faire en sorte qu’Excel soit rendu invisible : on ne le verra pas dans la barre de tâches, même si son processus est actif. Ensuite on va initialiser le classeur, qui contiendra ses 3 feuilles. La première est automatiquement “activée”.

Ce qu’on fait dans l’étape ci-dessus :

  • On modifie la propriété OLE “Visible” à “OLEFaux” (le code étant alors “monFichierXls>>Visible=OLEFaux”), afin qu’Excel soit masqué.
  • On va ajouter un classeur, grâce à la méthode Workbooks.Add(). Si on veut traduire cela en code WLangage, cela donne alors quelque chose comme : “monFichierXls>>WorkBooks>>Add()”. Réf : Plus d’informations à propos de cette méthode.
  • On va définir le nom de la feuille active grâce à la propriété Application.ActiveSheet.Name. C’est toujours le même principe : on utilise l’opérateur “>>” à chaque niveau. Du coup, on obtient quelque chose comme “monFichierXls>>ActiveSheet>>Name = VALEUR” en WLangage.

Après, on peut s’amuser à définir le contenu d’une cellule à partir des indices de ligne et de colonne. Dans Excel, les colonnes sont nommées de A à ZZ mais sont indicées à partir de 1, tout comme les lignes. On peut aussi modifier la taille de la police, l’apparence, la couleur de fond, etc.

Pour interagir avec la cellule qui nous intéresse, on utilise ActiveSheet.Cells(x, y). X étant l’indice de ligne et Y l’indice de colonne. Chaque cellule possède un nombre d’éléments qui peuvent être édités, telles que Font (pour la police), HorizontalAlignment (pour définir l’alignement du texte par exemple), Interior, etc. C’est comme ça qu’on définit la taille de la police…

Quelques exemples :

  • monFichierXls>>ActiveSheet>>Cells(1,2)>>Font>>Bold = True
  • monFichierXls>>ActiveSheet>>Cells(1,2)>>Font>>Size = 16
  • monFichierXls>>ActiveSheet>>Cells(1,2)>>Interior>>ColorIndex = 56

Détail des exemples ci-dessus : le premier met la police de la cellule B1 (1, 2) en gras. Le second définit sa taille à 16. Enfin, le troisième définit la couleur de fond numéro 56 selon l’index de couleurs défini dans Excel. Voici la palette :

Il est bien sûr possible d’indiquer sa propre couleur avec la propriété Color, dans laquelle on stocke la valeur de la fonction RGB() proposée par Windev. Le site Excel-Pratique donne des exemples de valeurs à utiliser avec cette fonction…

Pour mettre en page, on peut jouer avec les propriétés de l’objet ActiveSheet.PageSetup. La propriété Orientation permet de choisir entre le mode paysage (ici, la valeur est alors égale à 2) ou portrait. Les propriétés Left*, Top*, Bottom* et RightMargin permettent de définir les marges. Enfin la propriété Zoom permet de définir la valeur du zoom ce qui peut aider pour faire rentrer la feuille complète sur la page.

Enfin pour terminer et sauvegarder le fichier Excel, il faut désactiver l’affichage des alertes, appeler la méthode “SaveAs()” en indiquant en paramètre le nom du fichier, réactiver les alertes, fermer le classeur et quitter Excel. Il ne restera plus qu’à détruire l’objet !

Dans l’ordre :

  • On a désactivé les alertes : “monFichierXls>>DisplayAlerts = False”.
  • On a sauvegardé le fichier à l’aide de SaveAs(). Plus d’informations dans la documentation officielle située ici : référence MSDN FF841185.
  • Réactivation des alertes.
  • Fermeture du classeur : “monFichierXls>>ActiveWorkbook>>Close()”.
  • Fermeture d’Excel : “monFichierXls>>Quit()”.
  • Destruction de l’objet avec le mot-clé “libérer”.

Il est bien sûr possible d’en faire plus, car il existe de nombreuses méthodes, de nombreux objets, et un tas de propriétés associées à ceux-ci ! On peut par exemple définir une formule, modifier un ensemble de cellules plutôt qu’une seule à la fois, et encore bien d’autres choses. Bon développement à tous !

[Excel 2007] Problème de réparation automatique

[Excel 2007] Problème de réparation automatique

Nous avons été face à un problème étrange avec Excel sur plusieurs ordinateurs exécutant une même version d’Office Professionnel 2007 SP3, alors que d’autres machines ne présentaient aucun symptôme avec les mêmes fichiers ouverts, également avec la version ci-dessus.

En effet, le message “Excel a pu ouvrir le fichier en réparant ou en supprimant du contenu illisible” (en anglais : Excel was able to open the file by repairing or removing the unreadable content) apparaissait automatiquement lors de l’ouverture de classeurs, alors que ceux-ci avaient déjà été ouverts auparavant sans aucun souci, même sur d’autres machines. Après réparation automatique, tous les styles, toutes les mises en formes et même les tableaux croisés dynamiques, avaient disparu.

Microsoft décrit des causes probables qui produiraient ce phénomène : KB973932.

Dès le début, nous avons suivi plusieurs pistes, qui se sont avérées infructueuses. Peut-être pourront-elles vous dépanner :

  • Désactiver la réparation automatique pour le classeur Excel et l’enregistrement régulier des versions. Pour cela, rendez-vous dans le menu Office, puis “Options Excel”, section “Enregistrement” et décochez la case “Enregistrer les informations de récupération toutes les X minutes”.
  • Utilisation du Microsoft Fixit 50905 décrit dans la KB2553026. Malheureusement, nous n’avons pu installer l’outil car la version d’Office que nous utilisons est bien trop récente. Il ne peut être appliqué que sur une version 12.0.6565 (ou inférieure du moins). Pour l’obtenir, cliquez sur le lien suivant : support Microsoft.
  • Supprimer des styles inutilisés avec VBA ou avec un outil. Cette méthode a effectivement supprimé certaines mises en forme superflues, mais n’a rien changé au problème. Dans tous les cas, ce n’est pas une mauvaise chose : cela nettoie votre classeur. L’outil XLStylesTool permet de réaliser cette action en un clin d’œil.

Suite à toutes ces manipulations, nous avons contacté Microsoft en … Roumanie! Nous avons envoyé quelques fichiers logs (des journaux d’évènements) afin qu’ils puissent les analyser et trouver la source du problème. Après investigation, ils nous ont envoyé une astuce qui semble avoir porté ses fruits.

A notre grande surprise, il s’agirait d’une incompatibilité avec le logiciel iTunes, développé par Apple. Effectivement, après vérifications, nous remarquons que les machines “touchées” possèdent toutes le logiciel fautif. Voici ce que nous vous proposons.

Plan d’action:
Ouvrez une fenêtre de l’explorateur et naviguez vers l’emplacement :
C:\Program Files (x86)\Common Files\Apple\Internet Services (Windows 7 x64)
C:\Program Files\Common Files\Apple\Internet Services (Windows 7 32 bits)
Renommez la DLL “ShellStreams.dll” en lui ajoutant l’extension « .old » pour qu’elle ne soit plus exécutée.

Merci à Microsoft pour le support ainsi qu’aux différents collègues qui sont intervenus.