Recherche sur le blog

lundi 16 novembre 2015

[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.

Aucun commentaire: