La première étape est l'extraction d'informations de l'arborescence des fils RSS du corpus. Grâce à la structuration imposée des données dans un fichier RSS, certaines zones du fichier peuvent être systématiquement ciblées pour en extraire le contenu. On verra qu'il existe deux façons d'extraire ces informations, ce qui a pour résultat la création de deux programmes distincts :
Le but est de produire deux types de sorties : un fichier TXT et un fichier XML contenant les titres et les descriptions des mises à jours à partir du corpus. Etant donné que les fils RSS appartiennent à différentes rubriques du journal (culture, sport etc.) un fichier de chaque type est produit pour chaque rubrique.
On a vu que les fichiers sont organisés en dossier selon la date et l'heure de mise à jour et selon la rubrique. Pour traiter chacun de ces fichiers, le programme doit identifier quels objets de l'arborescence sont des dossiers et lesquels sont des fichiers. 'if (-d $file)' identifie si c'est un dossier – dans ce cas, on parcourt encore l'arborescence en explorant ce dossier jusqu'à ce que tous les fichiers soient identifiés. Les fichiers sont identifiés par : 'if (-f $file)'.
La première solution (Pure Perl) nécessite une phrase de pré-traitement assez importante. Pour que le texte s'affiche correctement et afin de comparer du texte extrait de fichiers sources différents, il est d'abord nécessaire d'harmoniser le contenu des fichiers, c'est à dire :
La diversité des encodages et les problèmes qu'elle peut entraîner commencent à être très familiers. Il faudrait s'assurer que les fichiers soient tous écrits dans le même encodage au moment de la lecture et au moment de la sortie. Il faut un mécanisme qui détecte l'encodage afin de faire cela correctement et il y a deux manières de procéder :
Donc c'est avec la deuxième méthode qu'on va procéder. Et pour s'assurer qu'il n'a plus d'erreurs à l'ouverture du fichier au cas où aucun encodage ne serait détecté, le traitement qui suit appliquera uniquement sur les fichiers pour lesquels on peut l'identifier :
Maintenant, afin d'ouvrir chaque fichier dans son encodage d'origine, il est utile de le spécifier lors de son ouverture :
Il faut aussi s'assurer que l'encodage soit commun entre les fichiers traités. Quel que soit leur encodage d'origine, tous les fichiers seront convertis en UTF-8 (s'ils ne sont pas déjà en UTF-8). La bibliothèque XML UnicodeString possède une fonction (utf8) qui fait cette conversion sur la base de l'encodage d'origine fourni.
Bien que les fichiers soient tous structurés de la même façon avec les mêmes balises, il n'y a rien qui oblige les fichiers à avoir exactement le même formatage. Pourvu que les balises soient conformes aux règles de la syntaxe RSS, ‘whitespace' (des sauts de ligne, des tabulations et des espaces) ne changent rien par rapport à la bonne formation du document.
Ainsi, il existe des fichiers RSS où tout le contenu est sur une seule ligne, des fichiers où chaque balise a sa propre ligne, et rien n'empêche le passage à la ligne à l'intérieur d'une balise.
Par contre, le programme perl doit pouvoir manipuler tous les fichiers et parcourir automatiquement et systématiquement l'arborescence de chaque fichier, quelque soit le formatage. Alors il faut prévoir une étape pour les harmoniser. Le format le plus facile à manipuler pour notre programme est celui où tout le contenu est sur une seule ligne.
Pour supprimer les éventuels sauts de ligne :
Et pour coller les balises :
Les expressions régulières offrent un moyen très commode pour parcourir la structure arborescente des fichiers afin de viser certaines zones de texte et de les extraire. Pour extraire tous les titres et les descriptions, une boucle parcourt le fichier, repérant les parties du texte correspondant au motif spécifié. Les parenthèses permettent de viser certaines zones du texte afin de les isoler et les stocker séparément.
Ce motif cherche les parties du texte qui contiennent les balises <title></title> et <description></description> directement sous la balise <item>, et les parenthèses isolent le contenu de chacune de ces balises, le stockant respectivement dans les variables $1 et $2.
De cette manière, d'autres informations relatives au fichier peuvent être facilement extraits : la date d'édition et le nom du flux, qui se situent à l'intérieur de la balise 'channel'.
Ces informations peuvent être ajoutées dans les fichiers de sorties, mais la plus importante est la rubrique, puisque le but est de produire une sortie par rubrique ! Cette variable peut être utilisée pour nommer les fichiers de sortie et pour créer une variable par rubrique qui sert à stocker le contenu de chacune (en vue de faire une sortie globale).
Il existe une deuxième solution pour arriver au même résultat. C'est une méthode qui tient compte du fait que les fichiers soient des fichiers XML et aient une structure arborescente. La première solution n'en tient pas compte et utilise les expressions régulières pour extraire les nœuds d'une manière similaire à l'extraction du texte d'un fichier texte brut.
Cette deuxième solution utilise XML::RSS, un module désigné spécifiquement pour les fichiers RSS.
Les étapes sont principalement les mêmes : il faut parcourir l'arborescence du dossier, en traitant tous les fichiers XML. Les sorties sont pareilles : un fichier texte et un fichier XML par rubrique, contenant les titres et descriptions de chaque item.
Ce qui change est la manière d'extraire ces informations. Faire du fichier un objet XML::RSS permet d'exploiter la structure arborescente pour atteindre les nœuds et de produire un objet hiérarchique au lieu de l'objet plat produit par la méthode qui utilise les regex.
La première ligne crée un nouvel objet XML::RSS dont la référence est stockée dans la variable $rss. La deuxième signifie que l'objet à analyser en forme RSS est le fichier situé au chemin indiqué par $path.
L'objet RSS qui est créé est un tableau associatif qui contient des références vers d'autres références. Associer des références aux clés permet d'avoir des valeurs similaires au type 'liste' dans un tableau associatif, qui contient normalement des scalaires. Il est ainsi possible d'associer à un nœud 'item' des références vers les nœuds 'title' et 'description', qui sont contenus sous cette balise. Une boucle cherche tous les nœuds sous la balise 'items', et pour chaque nœud 'item' extrait le nœud 'title' et 'description'. Ceci se fait par l'opérateur 'flèche'.
La rubrique peut être extraite de la même manière :
L'avantage avec cette méthode est qu'il n'est pas nécessaire de faire l'harmonisation des fichiers (la suppression des sauts de lignes, les espaces entre les balises et le traitement des encodages différents). C'est le module XML::RSS qui gère ces étapes, et rend aussi la tâche de parcourir l'arborescence RSS plus facile. Un désavantage est que le déroulement du programme est plus chronophage.
Une fois les informations extraites, il faut veiller à leur bon affichage et à la non-duplication de ces informations.
Ayant déjà passé par une étape de transcodage, on pourrait se demander pourquoi il est nécessaire de faire une deuxième phase de nettoyage. Un premier nettoyage est nécessaire chez les rubriques. L'extraction de la rubrique se fait à l'intérieur du fichier et est de la forme : 'Le Monde.fr : à la Une' ou bien 'Europe - LeMonde.fr'. Ce qui nous intéresse est tout sauf ' : Le Monde.fr' ou ' - LeMonde.fr', qu'il faut enlever. Les rubriques vont être utilisées pour nommer des fichiers, donc il serait sage d'éviter des espaces et des caractères accentués. Pour simplifier, chaque rubrique est convertie en majuscules, tout espace supprimé, toute virgule remplacée par le tiret du huit et tout autre signe de ponctuation enlevé.
(La fonction shift enlève le premier élément de la liste d'arguments fournis et le renvoie.)
Les titres et les descriptions doivent également être nettoyés mais pas de la même façon. Ils contiennent certaines suites de caractères étranges, tels que <, & et >. Ce sont des entités XML : des caractères codés selon la spécification XML pour éviter que ces caractères spéciaux soient interpretés comme faisant partie de la structure du document.
Il y a cinq entités XML prédéfinies (HTML en spécifie davantage) :
Pour remplacer les références XML par les caractères qu'ils représentent, le texte est passé par une fonction qui utilise les expressions régulières pour substituer l'un pour l'autre.
Comme avec la fonction 'nettoyerRubriqes', la fonction, nommée nettoyerTexte fait une copie de l'argument donné (le texte à nettoyer) et remplace les entités XML une par une par les caractères correspondants :
Quelques remarques :
Il existe aussi un module perl téléchargeable qui permet de faire la même tâche : XML::Entities prend en argument le texte à décoder et renvoie dans une seule ligne le texte 'décodé' :
Le fait qu'il s'agisse de fichiers de mises à jour augmente la possibilité d'avoir des informations dupliquées dans les fichiers de sortie. Pour ne pas que de grandes quantités d'informations répétées influent faussement le résultat final, il faut un moyen de trier les informations déjà vues des informations nouvelles.
En perl les tableaux associatifs permettent d'associer une information unique à une valeur. En créant une de ces structures pour les titres et une autre pour les descriptions, il est possible de vérifier si les informations ont déjà été vues.
Les deux tableaux associatifs sont déclarés au début du programme :
Mais il est important de distinguer des informations dupliquées à l'intérieur d'une rubrique (qu'il faut éviter) des informations dupliquées à travers les rubriques, qu'il faut permettre. Si la même description appartient à deux rubriques, il faut un moyen de la faire apparaître dans les deux. Idéalement il faudrait un tableau associatif pour les titres et les descriptions de chaque rubrique, mais nommer les tableaux associatifs dynamiquement en utilisant la variable $rubrique est très compliqué en Perl. Une solution plus simple est d'utiliser un seul tableau pour tous les titres et un autre pour les descriptions et de préfixer chaque titre et chaque description de sa rubrique :
L'item sera traité uniquement si les tableaux associatifs ne contiennent pas à la fois le titre et la description pour cette rubrique.
N.B. Un tri est effectué juste avant cette étape pour éviter les items dont soit la description soit le titre est vide (ceci peut arriver si un des deux contient uniquement des caractères enlevés au moment du nettoyage). Autrement ces items pourraient poser un problème pour la comparaison de la non-duplication des informations. D'ailleurs on pourrait considérer plus logique d'écrire un item uniquement s'il y a toutes les informations disponibles (titre et description).
Plusieurs sorties sont produites :
Les sorties en format TXT ne contiennent - évidemment - aucune balise. Elles contiennent simplement une liste des titres et des descriptions. Au moment d'écrire les titres et les descriptions dans ces fichiers, il faut faire attention de les préfixer d'un point pour bien délimiter le début et la fin de chaque titre et chaque description.
Les sorties TXT par rubrique sont concatenées au fur et à mesure du déroulement du programme. Dans l'étape de l'extraction des informations, la rubrique de chaque fichier peut être identifiée et stockée dans une variable. Cette variable est utilisée pour nommer les fichiers. Une fois le chemin défini, il suffit de créer le fichier s'il n'existe pas déjà ou de l'ouvrir s'il existe et dans les deux cas d'écrire les titres et les descriptions, séparés de points. Le fichier global étant déjà ouvert, l'écriture vers ce fichier peut se faire directement après.
La sortie globale est ouverte juste avant le lancement de la procédure parcoursarborescencefichiers (qui effectue le traitement), concaténée en cours de marche (ci-dessus) et fermée une fois tous les fils RSS sont traités.
Les sorties en format XML doivent être bien structurées, avec des balises XML. Donc au moment de la sortie, il faut organiser les informations avec des balises appropriées.
Les sorties par rubrique sont concaténées en cours de route (comme avec les sorties TXT). Le même principe est utilisé pour désigner dans quel fichier il faut écrire. Mais cette fois-ci la structuration des données sont mises en évidence par la présence des balises : une balise 'fichier' (avec son nom et date), à l'intérieur de laquelle est une liste d'items : chaque balise 'item' contient son titre et sa description.
A la rencontre d'un nouveau fichier, ses informations sont extraites et la rubrique identifiée. Avant d'ajouter de nouveaux items, le fichier correspondant à la rubrique est créé (s'il n'existe pas déjà) et ouvert (s'il existe déjà). Dans le cas où le fichier vient d'être créé, la balise racine du fichier XML doit être ouverte, y compris d'autres informations jugées utiles pour la désignation du fichier. Dans les deux cas, puisqu'il s'agit du traitement d'un nouveau fichier, on écrit une balise ouvrante <file>, qui sera fermée à la fin du traitement du fichier.
Et à la fin du traitement du fichier :
Les items sont ajoutés un par un à l'intérieur de la boucle while. Chaque paire titre-description est écrite sous une balise <item> et chacune entourée de sa balise appropriée.
Pour assurer la bonne structuration de ces fichiers, il faut aussi fermer les balises ouvertes à leur création. Ceci doit se faire à la fin du programme, une fois que toutes les informations sont ajoutées. La boucle suivante parcourt le contenu du dossier de sortie et écrit les balises fermantes nécessaires pour tous les fichiers XML qui ne sont pas la sortie globale (qui sera traitée séparément).
La sortie globale XML est structurée par rubrique. Ceci veut dire que son contenu ne peut être écrit qu'à la fin du traitement de tous les fichiers. Pour chaque rubrique il doit exister une variable pour stocker tous les items associés à cette rubrique jusqu'à l'écriture dans le fichier à la fin du programme.
Bien que ça ne soit pas toujours considéré comme une décision très sage, je nomme dynamiquement les variables en utilisant la variable $rubrique. Il n'est pas certain non plus que cette méthode marche quand 'strict refs' sont activés. Mais pour cette tâche spécifique, il semble être une bonne idée - surtout parce qu'il est possible de retrouver toutes ces variables créées via les noms des fichiers créés.
Une fois tous les fichiers traités, la sortie globale peut être construite :
Pour l'écriture de chaque rubrique, on peut toujours exploiter la boucle pour la fermeture des rubriques, afin d'avoir la liste complète des rubriques :
A l'intérieur de la boucle, on écrit dans le fichier global une balise au nom de la rubrique actuelle et le contenu de la variable pour cette rubrique (une liste d'items contenant chacun un titre et une description). A la fin de la boucle il ne faut pas oublier de fermer toutes les balises du fichier !
Les deux méthodes d'extraction du contenu des fils seront testées, ce qui signifie l'écriture de deux programmes séparés :
Les compteurs à l'intérieur de chaque programme permettent de s'assurer qu'il y ait le même nombre d'items en sortie à la fin du programme. Heureusement, c'est le cas ! (ce qui montre que l'expression régulière est assez précise). Le nombre total des items en sortie est de....53 461, sachant que sans tenir compte des duplications il y en a plus de 130 000 !!
Les résultats de cette étape peuvent être présentés en format HTML après une transformation XSLT des sorties XML.
La feuille de styles XSL rattachée à chaque document XML transforme chaque rubrique en un tableau de titres et de descriptions, rangés par fichier :
0,2-3476,1-0,0 (Sat, 31 Mar 2012 14:25:08 GMT) | |
---|---|
Titre | Description |
Julie Delpy récidive | Les choix culture de "M", le magazine du "Monde"/Cinéma. "2 Days in New York" |
Faiseurs de culture : Sylvain Chomet à Alès | A la veille de la présidentielle, "Le Monde" donne la parole à ceux qui font bouger les régions dans le domaine culturel |
"Hunger Games" : l'apocalypse pop servie par le marketing | La franchise entend détrôner les sagas "Twilight" et "Harry Potter" auprès des ados. Décryptage d'un lancement savamment élaboré |
... | ... |
0,2-3208,1-0,0 (Sun, 01 Apr 2012 17:18:03 GMT | |
---|---|
Titre | Description |
Ligue 1 : Lille croit de nouveau au titre | En battant Toulouse dimanche à domicile grâce à une nouveau festival d'Eden Hazard , les Lillois ont démontré qu'il ne fallait pas les oublier dans la course au titre en Ligue 1, à huit journées du dénouement |
Mort de la résistante Lise London | La veuve d'Artur London, dont le procès stalinien a été rendu célèbre par son livre et le film "L'Aveu", est morte à l'âge de 96 ansl |
"Affaire Merah : l'avocate du père dit détenir des vidéos prouvant "la liquidation" du tueur | Selon Me Zahia Mokhtari, "Merah a été manipulé et utilisé par les services français et a ensuite été liquidé pour que la vérité ne voie pas le jour" |
... | ... |