16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » ENST de Bretagne Technopôle Brest-Iroise 29280 PLOUZANÉ Méta-calendrier automatique pour portail www Projet d’ingénierie Isabelle KERVELLA Mastère ISIC (Ingénierie des Systèmes Informatiques Communicants) Soutenue le 21 mars 2002 Encadrant : Ronan KERYELL 1 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Résumé L’objet de ce projet est de développer un outil qui collecte automatiquement des données dans des sites publiés sur Internet et les rassemble dans un portail. Si le format HTML est parfaitement adapté à la présentation de documents simples sur Internet et à la navigation entre les pages, il n’offre pas une présentation structurée des données. Mélangeant le fond, la forme et les données, il n’est pas aisé d’extraire l’information utile. Le travail réalisé dans le cadre de ce projet montre que l’utilisation d’un wrappeur pour traduire un document non structuré dans un format XML, puis d’un parseur pour extraire l’information, constitue une solution à ce problème. Mots clés : HTML, extraction des données, wrapping, XML, parsing, API JAXP 2 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Table des matières 1 CONTEXTE .................................................................................................................................................. 4 1.1 COMPREHENSION DU BESOIN ................................................................................................................... 4 1.1.1 Analyse des sources, détection de l’information utile et extraction des données ................................ 5 1.1.2 Stockage des données .......................................................................................................................... 5 1.1.3 Nettoyage des données ........................................................................................................................ 5 1.1.4 Représentation visuelle des données ................................................................................................... 6 1.1.5 Paramétrage de la collecte / administration ....................................................................................... 6 1.2 2 ANALYSE FONCTIONNELLE ...................................................................................................................... 6 SOLUTIONS TECHNIQUES PROPOSEES ............................................................................................. 8 2.1 ANALYSE DE LA SOURCE, DETECTION DE L’INFORMATION UTILE ET DEFINITION D’UN FORMAT UNIFIE ... 9 2.1.1 Site analysé ......................................................................................................................................... 9 2.1.2 Détection de l’information utile, écriture du fichier de description .................................................... 9 2.1.3 Récupération de l’information utile dans un fichier au format XML ................................................ 11 2.2 LE PARSING ............................................................................................................................................ 12 2.2.1 Les APIs des parseurs ....................................................................................................................... 13 2.2.2 Développement du parseur en Java .................................................................................................. 14 3 CONCLUSION............................................................................................................................................ 16 4 BIBLIOGRAPHIE ...................................................................................................................................... 17 Table des figures Figure 1 : schéma des principales étapes du projet ................................................................................................ 6 Figure 2 : liste des événements, classés par date, du site http://www.bzh5.com/gouel/degemer.php ................... 10 Figure 3 : Structure du calendrier ........................................................................................................................ 11 Figure 4 : l’information utile est recueillie dans un fichier XML ......................................................................... 12 Figure 5 : rôle d’un parseur XML & API DOM ................................................................................................... 13 Table des annexes ANNEXE 1 ............................................................................................................................................................ 18 ANNEXE 2 ............................................................................................................................................................ 23 ANNEXE 3 ............................................................................................................................................................ 29 3 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Partie 1 1 Contexte Le site trad.org est un portail de musique traditionnelle. La rubrique Bals & Concerts a pour vocation d’informer des principaux événements folkloriques. Dans sa version actuelle, la rubrique est constituée de liens hypertextes qui pointent vers des calendriers présentés dans des sites Internet d’événements. Les nombreuses sources d’informations et la très grande disparité de ces informations rendent difficile la recherche de données précises. L’objet de ce projet est d’offrir une vue globale et à jour de ces informations, en développant pour ce portail, un calendrier rassemblant les événements de l’ensemble des sites cibles. Le projet ne trouve tout son sens que s’il permet l’extraction et la mise en forme automatiques des données. L’objectif de ce travail est donc de trouver des solutions pour extraire l’information utile des différents sites Internet, la stocker et la représenter visuellement sous la forme d’un calendrier sur le portail trad.org. La principale difficulté est bien sûr de collecter des données hétérogènes de manière correcte et cohérente. 1.1 Compréhension du besoin Ce projet couvre plusieurs aspects, détaillés ci-après : l’extraction des données le stockage des données le nettoyage des données la représentation visuelle des données le paramétrage de la collecte / l’administration 4 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » 1.1.1 Analyse des sources, détection de l’information utile et extraction des données Les données sont extraites de sites Internet (protocole http). Le fond et le format des données ne sont soumis à aucune norme. Ils diffèrent selon la source d’information et ne présentent pas de stabilité dans le temps. L’extraction des données inclut plusieurs étapes : L’analyse de la source (format HTML) La détection de l’information utile La définition d’un fichier de description propre à la source analysée La définition d’un format unifié pour toutes les données à collecter Le wrapping Le parsing Elle implique également de tenir compte de différents paramètres : Le type de source (page HTML statique, résultat d’une requête) Les racines de l’information (adresse du site distant et protocole utilisé) Les caractéristiques de la connexion (port pour le protocole utilisé, proxy, firewall, login, mot de passe, …) Le paramétrage de l’extraction : périodicité, granularité (incrémentale ou complète), chargement des données (en ligne, hors ligne), … 1.1.2 Stockage des données Deux modes de stockage peuvent être envisagés : Le stockage dans une base de données relationnelle (MySQL, …) Le stockage dans une base de données XML 1.1.3 Nettoyage des données Le mécanisme de nettoyage des données couvre : L’identification des doublons grâce à la corrélation des calendriers La détection des annulations La détection des données obsolètes 5 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » 1.1.4 Représentation visuelle des données Elle doit permettre à l’utilisateur de visualiser un jeu de données en fonction de critères à préciser (date, type d’événement, lieu, …) 1.1.5 Paramétrage de la collecte / administration La partie administration englobe notamment : La définition des sources, outils… Les règles d’extraction, de nettoyage,… La politique de mise à jour, rafraîchissement Le cycle de vie de la donnée, fraîcheur de la donnée 1.2 Analyse fonctionnelle L’outil à développer peut être vu au travers des étapes décrites dans le schéma ci-dessous : Données HTML (source HTTP) Wrapper Grammaire (fichier .nf) (programme Java) Ecrite après analyse du code source : Analyse de la sémantique Résultats (Fichiers de sortie) .txt Nettoyage des données - Détection des doublons - Annulation des données obsolètes <Calendrier> <Evenements Date= ‘’01.01.02’’> <Evenement Type=’’Fest-noz’’ Lieu=’’Brélès’’ Acteurs=’’Kael’’> <\Evenement> <\Evenements> <\Calendrier> Parseur Stockage des données (programme Java) Requête Formulaire de reche rche .xml Résultat de l a requête Affichage des réponses Portail Trad.org Figure 1 : schéma des principales étapes du projet 6 n fichiers XML (format unifié) 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Le travail réalisé jusqu’à présent couvre la phase d’extraction des données, de l’analyse des sources d’information au parsing. Les solutions techniques choisies font l’objet de la seconde partie. Pour alléger l’exposé, les programmes et autres données techniques sont placés en annexes. 7 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Partie 2 2 Solutions techniques proposées L’information à extraire est contenue dans des pages écrites en HTML (HyperTextMarkup Language). Par essence, ce langage n’est pas destiné au stockage des données, mais à leur affichage et à la liaison entre les différentes parcelles d’information. De ce fait, mais aussi en raison du manque de rigueur dans l’écriture du code, les items dans les pages HTML sont difficiles à capturer par des parseurs grammaticaux ordinaires. Pour convertir un texte mal structuré en une collection d’objets de base de donnée, les étapes clés sont l’identification des informations contenues dans le texte, l’extraction des données et la construction d’une représentation qui pourra être manipulée par un langage de requête. Ce procédé, appelé « wrapping » se fait grâce à un module logiciel, l’adaptateur (ou wrapper). Plusieurs projets portent sur la génération automatique de wrappers. Les principaux (ARANEUS [1], XWRAP [2], TSIMMIS [3], W4F [4]) permettent de concevoir un outil paramétrable selon le modèle et les sources de données. L’outil utilisé dans le cadre de ce projet est Araneus. Cet outil s’appuie sur un formalisme, appelé Minerva1, permettant de générer un wrapper à partir de sources de données Web et semi-structurées. Sa particularité est qu’il tente de combiner les avantages d’une approche déclarative, basée sur une grammaire, et la flexibilité d’une programmation procédurale pour le traitement des hétérogénéités et des exceptions. 1 Minerva a été développé dans le framework d‘Araneus, un projet de recherche de l’Université de Romes 8 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Il propose un compromis entre une approche déclarative et une programmation procédurale, en incorporant dans un parser grammatical, un mécanisme de traitement des exceptions. Cela se fait en annotant les productions de grammaire avec une clause d’exception, contenant un morceau de code procédural. Durant le parsing, si une des productions échoue, une exception est levée et la clause d’exception correspondante est invoquée. Le code est alors exécuté afin de tenter de restructurer le document source et de reprendre le parsing. 2.1 Analyse de la source, détection de l’information utile et définition d’un format unifié La première phase du travail repose sur l’analyse du fichier source (HTML) et l’écriture d’un fichier de description (ou grammaire). 2.1.1 Site analysé Parmi les sites à analyser, certains seront difficilement exploitables 2. C’est le cas des sites dont les données textuelles ne présentent pas de logique de classement ou n’apparaissent que de manière facultative, et pour lesquels l’extraction de l’information utile impose d’en connaître le sens. Le site (http://www.bzh5.com/gouel/degemer.php), choisi ici pour tester l’outil, présente une structure simple. Réalisé en PHP, il se prête facilement à l’extraction de données. Les informations sont le résultat d’une requête et sont présentées dans un tableau de manière homogène. Toutefois, comme il a été dit précédemment, l’outil Araneus est conçu pour traiter les exceptions et pourra être utilisé pour extraire l’information de pages moins bien structurées. 2.1.2 Détection de l’information utile, écriture du fichier de description Le site analysé présente des événements classés par date. Chaque date fait partie d’une liste, dont les balises constituent un point de repère. Pour une date donnée, les événements sont présentés dans un tableau. Chaque événement est décrit par le type d’événement (fest-noz, …), le lieu (ville en breton, [département], ville en français), les acteurs (groupe, artiste). Un lien permet d’accéder à un complément d’information. 2 L’analyse des sites est présentée en annexe 3 9 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Figure 2 : liste des événements, classés par date, du site http://www.bzh5.com/gouel/degemer.php Un événement se caractérise donc par une date, un type, un lieu et des acteurs. Ces données constituent l’information utile que l’on doit extraire du code source HTML, présenté dans l’annexe 1 (§ 2). La grammaire3 (fichier au format .nf) est générée en exploitant les balises caractéristiques encadrant les données à récupérer. C’est à partir de cette grammaire que le wrapper sera ensuite construit. La grammaire est présentée en annexe 1 (§ 3). La première partie de cette annexe (§ 1) répertorie les principales commandes utilisées pour construire le wrapper à partir de la grammaire, puis pour extraire les données et les recueillir dans un fichier de sortie. 3 ce rapport ne met volontairement pas l’accent sur la réalisation de la grammaire, car l’outil Araneus propose dans sa documentation, un très bon tutorial l’expliquant et mettant notamment l’accent sur le traitement des exceptions. 10 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » 2.1.3 Récupération de l’information utile dans un fichier au format XML Le wrapper Araneus génère en sortie un fichier au format .txt ou .xml. Le format XML présente de multiples avantages. Contrairement à HTML, XML définit un format de données hautement structuré, qui ne mélange pas l’information et la mise en forme du document. La phase de conception nous oriente sur la structure logique du calendrier. La racine du document XML est représentée par l’objet Calendrier. Cet élément peut posséder une infinité d’enfants incarnés par les objets Evenements, caractérisé par l’attribut Date. A chaque date correspond une infinité d’enfants Evenement, dont les attributs sont le Type, le Lieu et les Acteurs. Calendrier Evenements Date Evenement Type Lieu Acteur Evenement Type Lieu Acteur Evenements Date Evenement Type Lieu Acteur Figure 3 : Structure du calendrier 11 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Le fichier XML4 est généré selon la structure présentée ci-dessus : Figure 4 : l’information utile est recueillie dans un fichier XML La séparation du contenu et de la forme permet d’extraire facilement les informations du document par un simple parsing. 2.2 Le parsing Un parseur [5], [6] est un programme capable de récupérer des informations contenues dans un fichier XML. Un jeu d’instruction vise à extraire les données sans avoir à s’occuper de la syntaxe du XML. Le principe des parseurs est le suivant : on donne l’appellation de la balise, et l’on obtient en retour la valeur comprise entre cette balise ouvrante et sa jumelle fermante. Le parseur est utilisé par l’application pour traiter les données XML. Les APIs jouent le rôle d’interface. Il existe 2 types de parseurs, qui utilisent des APIs distinctes : 4 A noter que le fichier XML généré comporte en première ligne le chemin du fichier source qui donne lieu à un message d’erreur. Le caractère « & », qui n’est pas interprété, est remplacé par &amp. Ces corrections ont été apportées manuellement. Dans la suite du projet, il faudra traiter plus élégamment ces deux cas. 12 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » le premier type de parseur compile l’ensemble du document et construit une représentation sous forme d’arbre d’objets (les attributs et méthodes permettent la manipulation de la structure logique et de l’information contenue dans le document). Il utilise l’API DOM. Le second type lit le flot de données XML en entrée, reconnaît et interprète les balises. Ce modèle, appelé « traitement dirigé par les événements », utilise l’API SAX. La figure ci-dessous met en évidence le rôle du parseur et de l’API : Figure 5 : rôle d’un parseur XML & API DOM 2.2.1 Les APIs des parseurs Les APIs des parsers [7] sont des composants logiciels permettant d’accéder facilement aux données contenues dans un document XML. C’est le but de SAX (Simple API for XML) et de DOM (Document Object Model). JAXP est une API qui rend le code d’une application XML indépendant du parser utilisé. Le principe, les avantages et inconvénients des principales APIs sont présentés dans le tableau ciaprès. 13 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » SAX (Simple API for XML) DOM (Document Object Model) JAXP (Java API for XML Parsing) 2.2.2 Principe Avantages et inconvénients On accorde au parser SAX des objets dont les méthodes (implantant des interfaces précises) sont appelées par le parser lorsque certains événements se produisent au cours du parsing du fichier XML. SAX est très rapide, mais ne permet pas de transformer l’arbre lors du parsing (il ne fait que consommer les données). La norme permet d’écrire des applications indépendantes du parser utilisé (il permet de produire du code standard qui s’adapte, sans recompilation. DOM permet de représenter un document XML sous forme d’un arbre d’objets en mémoire. Il définit une API pour parcourir et modifier l’arborescence. DOM est indiqué pour des applications modifiant l’arbre du document (ex : éditeur graphique de fichiers XML). Quelques défauts : il est lent, gourmand en mémoire ; la norme est incomplète. API mise au point par Sun pour le parsing XML afin de résoudre les problèmes de dépendance du code au parser. Son API est une enveloppe pour rendre le code d’une application XML indépendant du parser utilisé. Elle encapsule la création et le paramétrage des parsers SAX et DOM. Le code est totalement indépendant du parser utilisé et fonctionne avec tout parser conforme à l’API JAXP. Développement du parseur en Java Le parseur développé ici et présenté en annexe utilise l’API JAXP. Une première partie du programme parse et charge les informations dans un document objet, qui désigne un arbre de nœuds contenant les données et la structure de l’information. Les classes appartenant au package javax.xml.parsers, utilisées dans le programme sont décrites cidessous : - DocumentBuilderFactory définit une API de construction qui permet aux applications d’obtenir un parseur qui produit les arbres d’objet DOM à partir du document XML - DocumentBuilder définit l’API d’obtention de l’instance de document DOM à partir du document XML - FactoryConfigurationError informe des erreurs de configuration - ParserConfigurationException informe des problèmes sérieux de configuration 14 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » La structure DOM est ensuite parcourue, nœud par nœud grâce à 2 méthodes essentielles : getNodeName( ) et getNodeValue( ). Le traitement du nœud racine, des nœuds enfants et attributs (nœuds sans enfant) permet successivement de parser l’ensemble du fichier XML. Les classes java qui constituent le parseur sont présentées dans l’annexe 2. 15 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » 3 Conclusion Ce projet couvre plusieurs facettes allant de l’extraction des données à la visualisation des informations dans le portail. Le travail présenté dans ce rapport englobe l’analyse du besoin et offre des solutions pour l’extraction des données, constituant la première phase du projet. Les autres étapes n’ont pas été traitées. Une réflexion menée sur le stockage des données montre que deux solutions simples peuvent être envisagées. Comme nous le savons, XML constitue une bonne méthode de structuration des données. La nature structurelle des documents XML se révèle propice à l’emploi d’un langage de requêtes pour accéder à des éléments de l’arbre. Xpath, le pendant de SQL pour XML, permet d’opérer des recherches très poussées sur les documents XML. Cette méthode peut être combinée à une base de données relationnelle, telle que MySQL, qui offre elle aussi des avantages, tels que la facilité de gestion, la fiabilité des fonctionnalités et de la sécurité. 16 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » 4 Bibliographie [1] ARANEUS : http://www.difa.unibas.it/araneus [2] XWRAP : http://www.cc.gatech.edu/projects/disl/XWRAP/xwrap.html [3] TSIMMIS : http://www-db.stanford.edu/tsimmis/ [4] W4F : http://db.cis.upenn.edu/W4F/ [5] Michel Casabianca « Développement XML en Java sous Linux » http://www.sdv.fr/pages/casa/html/java-xml.html [6] O. Aboukhaled, C. Vanoirbeek « Gestion de documents XML » [7] API JAXP (Java API for XML Parsing) http://java.sun.com/xml/jaxp/ 17 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » ANNEXE 1 1- Araneus : guide des commandes utilisées a- Utilisation de mwg mwg est une classe Java, utilisée pour générer un wrappeur (une classe java) à partir d’une grammaire (fichier .NF). Elle utilise un fichier de propriétés (minerva/minerva.properties) qui, par une ligne de commande, compile le source Java généré (minerva.mwg.compiler=javac). Il s’utilise de la manière suivante : java mwg INPUTFILE OUTPUTWRAPPER Cette commande génère à partir du code .NF (INPUTFILE) le wrapper correspondant dans un fichier (OUTPUTWRAPPER). Un exemple : java mwg trads\NFFiles\test.nf test.java Cette commande produit, dans le répertoire courant, un wrapper appelé « test.java» à partir des spécifications se trouvant dans le fichier : "trads\NFFiles\test.nf". b- Extraction des données On utilise ensuite la commande suivante pour extraire les données en utilisant le wrapper : Usage: java <wrapper> NT SOURCE ... Cette ligne « wrappe » le document source (fichier stocké localement ou URL). NT est le « root » utilisé pour débuter le parsing. Le wrapper se connecte à la source, extrait les données et retourne le résultat. Un exemple : java test S trads\html\capture1.htm c- Format de sortie Les données extraites peuvent être présentées dans un fichier au format XML, en utilisant out.print(). Pour générer le fichier XML : java test S trads\html\capture1.htm > test.xml 18 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » 2- Source HTML de la page analysée (http://www.bzh5.com/gouel/degemer.php) <table width="95%" border="1" cellspacing="0" cellpadding="5" align="center" class=m12 bordercolor="#006600"> <tr valign="top"> <td bgcolor="#FFFFFF"> <b> 224 réponses trouvées</b> en Bretagne.</font><div align=center>&nbsp;&nbsp;&nbsp;&nbsp;<span class=m13>Page </span><span class=m13><b>1</b> </span><a href="#" onClick="document.ff.lech.value=10;document.ff.kum.value='100';document.ff.submit()"><span class=m13>2</span></a> <a href="#" onClick="document.ff.lech.value=20;document.ff.kum.value='100';document.ff.submit()"><span class=m13>3</span></a> [etc…] onClick="document.ff.lech.value=10;document.ff.kum.value='100';document.ff.submit()"><img src="davdehou.gif" border=0 align=absbottom></a>&nbsp; </div> <font color=#663333 class=m12><b>&#149;&nbsp;Dimanche 10 février 2002</b> <a href="diskkart.php?yezh=1&sizh=10022002&petra=1">Carte de ce jour</a></font> <table border=1 Cellpadding=1 Cellspacing=0 width=90% class=m12 align=center> <tr bgcolor="#FFFFCC"> <td width=4% nowrap><div align=center><b>Fest-deiz</b></div></td> <td width=30%><div align=center><b></b><br>Ar C'hembod [22]<br> <span class=m10>(Le Cambout)</span></div></td> <td><table border=0 Cellpadding=4 Cellspacing=0 class=m12><tr><td> avec :&nbsp;</td> <td>Les accordéonistes diato du CADB<br></td></tr></table></td> <td width=16% nowrap><div align="center"><a href='diskfest.php?n=603&yezh=1'><img src="klkart.gif" width="28" height="21"border="0"><br>Détails et carte</a></td> </tr> <tr bgcolor="#FFFFFF"> <td width=4% nowrap><div align=center><b>Fest-deiz</b></div></td> <td width=30%><div align=center><b></b><br>St-Karadeg [22]<br> <span class=m10>(St-Caradec)</span></div></td> <td><table border=0 Cellpadding=4 Cellspacing=0 class=m12><tr><td> avec :&nbsp;</td> <td>Kasadenn<br>Les Chantous d'Loudia<br>Gaïa<br></td></tr></table></td> <td width=16% nowrap><div align="center"><a href='diskfest.php?n=679&yezh=1'><img src="klkart.gif" width="28" height="21"border="0"><br>Détails et carte</a></td> </tr> [etc…] </table> <br> <font color=#663333 class=m12><b>&#149;&nbsp;Samedi 16 février 2002</b> - <a href="diskkart.php?yezh=1&sizh=16022002&petra=7">Carte de ce jour</a></font> < table border=1 Cellpadding=1 Cellspacing=0 width=90% class=m12 align=center> <tr bgcolor="#FFFFCC"> <td width=4% nowrap><div align=center><b>Fest-noz</b></div></td> <td width=30%><div align=center><b></b><br>Pleneventer [22]<br> <span class=m10>(Plaintel)</span></div></td> <td><table border=0 Cellpadding=4 Cellspacing=0 class=m12><tr><td> avec :&nbsp;</td> <td>Bizibul<br>L'Echo du Gouet<br>Kael<br></td></tr></table></td> <td width=16% nowrap><div align="center"><a href='diskfest.php?n=524&yezh=1'><img src="klkart.gif" width="28" height="21"border="0"><br>Détails et carte</a></td> </tr> </table> <p>&nbsp;</p></td> <td width="5%">&nbsp;</td> </tr> </table> </td> 19 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » <td valign=top width=3% align=right> <img src="/skd/kornnd.gif" width=20 height=20></td> </tr> <tr> <td valign=top width=2% height=14 bgcolor="#FFFFCC"><img src="/skd/traonkl.gif" width=20 height=20></td> <td width=18% class=bih height=14 valign="top" bgcolor="#FFFFCC">&nbsp;</td> <td width="77%"> <div align=right><i>www.fest-noz.net est un service gratuit proposé par <a href=http://www.bzh5.com>www.Bzh5.com</a></i></div> </td> <td valign=top width=3% align=right height=14><img src="/skd/korntd.gif" width=20 height=20></td> </tr> </table> <p>&nbsp;</p> </body></HTML> 20 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » 3- Grammaire générée (fichier au format .nf) après analyse du code HTML //suppression des codes genants sous Windows options { REMOVE_BLANKS TABULATOR("[","\t","]\n") } PAGE test //decomposition des traitements pour identifier: //dans un premier temps la date de creation du document //dans un second temps la date des evenements $S: { out.print("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"); } $TraitementDate { out.print("<Calendrier>"); } $TousResultats { out.print("</Calendrier>\n"); }; //Syntaxe : Mercredi 20 février 2002 $TraitementDate: *<div[ ]align=right><font[ ]class=m11[ ]color=#FFFFFF><b>$DateComplete</b>[&nbsp;]</font></div>?; $TousResultats: ( $TraitementPeriode $TableResultats )+ ; //Syntaxe : <font color=#663333 class=m12><b>&#149;&nbsp;Samedi 2 février 2002</b> - <a href="diskkart.php?yezh=1&sizh=02022002&petra=7">Carte de ce jour</a></font> $TraitementPeriode: *<font[ ]color=#663333[ ]class=m12><b>&#149[;]&nbsp[;]$DateComplete { out.print("<Evenements Date=\"" + $DateComplete + "\">\n"); } </b>[ ]-[ ]<a[ ]href="diskkart.php?yezh=1&sizh=02022002&petra=7">Carte[ ]de[ ]ce[ ]jour</a></font>? ; //{ out.print($Journee+" "+$DateJour+" "+$Mois+" "+$Annee);} //{ out.print("<Evenements Date=\""); } $DateComplete { out.print("\">\n"); } //Syntaxe : <table ...> // <tr ...> // <td ...> TYPE EVENEMENT ... </td> // <td ...> // <td> // <table ...> // <tr> // <td> // <td> LES ACTEURS ... </td> // </tr> // </table> // <td> // <td ...> non utilise // </td> // </tr> // ... (on recommence autant de fois) // </table> //$TableResultats: $EnteteTable ($CorpsTable)+ $PiedTable ; $TableResultats: $EnteteTable ($CorpsTable)+ $PiedTable { out.print("</Evenements>\n"); }; 21 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » $EnteteTable: *<table[ ]border=1[ ]Cellpadding=1[ ]Cellspacing=0[ ]width=90%[ ]class=m12[ ]align=center>; $CorpsTable: <tr[ ]bgcolor="(#FFFFCC|#FFFFFF)"> <td[ ]width=4%[ ]nowrap><div[ ]align=center><b> $TypeEvt { out.print("<Evenement Type=\"" + $TypeEvt + "\""); } </b></div></td> <td[ ]width=30%><div[ ]align=center><b></b><br> $LieuBZH [[]$Departement[]] <br><span[ ]class=m10>[(]$LieuFR { out.print(" Lieu=\"" + $LieuFR + "\""); } [)]</span></div></td> <td> <table[ ]border=0[ ]Cellpadding=4[ ]Cellspacing=0[ ]class=m12> <tr> <td>avec[ ][:]&nbsp[;]</td> <td> $Artist{ out.print(" Acteurs=\"" + $Artist); } <br>( $Artiste <br> { out.print(", " + $Artiste); } )* { out.print("\">\n"); } </td> </tr> </table> </td> <td[ ]width=16%[ ]nowrap><div[ ]align="center">$Divers</a></td> </tr> { out.print("</Evenement>\n"); } ; $PiedTable: *</table> ? ; //factorisation du traitement des dates $DateComplete: $Journee[ ]$DateJour[ ]$Mois[ ]$Annee; //decomposation des dates $Annee: \d\d\d\d; $DateJour: (\d)+; $Mois: [A-Za-zé]+; $Journee: [A-Za-z]+; //Le type d evenement a traiter $TypeEvt: [A-Za-z0-9-éèà]+; //Le lieu $LieuFR: [A-Za-zéèà '"-]+; $LieuBZH: [A-Za-z0-9éèêà '"-]+; $Departement: (\d)+; //Liste des artistes $Artist: [A-Za-z0-9-/& éèàêï'"]+ ; $Artiste: [A-Za-z0-9-/& éèàêï'"]+ ; //... rien a faire $Divers: *(?</a></td>)?; //traitement des exceptions END 22 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » ANNEXE 2 Code source des classes du parseur ParsCalendrier.java package calendrier; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import java.io.*; import org.w3c.dom.*; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.Vector; import java.util.Date; /** * Cette classe realise le parsing XML */ public class ParsCalendrier { private static Document document; /* chemin du fichier XML a parser */ public static String S_PATH = "xml/test.xml"; /* activation de la trace */ private static final boolean DEBUG = true; /* constantes de recherche dans le fichier XML */ private final static String S_CALENDRIER = "Calendrier"; private final static int I_EVTS_NB = 1; private final static String S_EVTS = "Evenements"; private final static String S_EVTS_DATE = "Date"; private final static int I_EVT_NB = 3; private final static String S_EVT = "Evenement"; private final static String S_EVT_TYPE = "Type"; private final static String S_EVT_LIEU = "Lieu"; private final static String S_EVT_ACTEURS = "Acteurs"; 23 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » //Création d'un vecteur pour stocker les différentes dates du calendrier public static Vector listeEvenements=new Vector(); public static void main(String [] args) { System.out.println("Demarrage du processus. SVP, attendez......."); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse( new File(S_PATH) ); } catch (SAXException sxe) { // Error generated during parsing) Exception x = sxe; if (sxe.getException() != null) x = sxe.getException(); x.printStackTrace(); } catch (ParserConfigurationException pce) { // Parser with specified options can't be built pce.printStackTrace(); } catch (IOException ioe) { // I/O error ioe.printStackTrace(); } // on peut travailler maintenant sur le document mis en memoire // on met en memoire tt ce ont on a besoin traiterDocument(); // on presente les resultats a l ecran // presenterResultats(); System.out.println("le processus est termine."); } // main /** * cette methode est la cle de voute de l'application * elle recupere une liste de tous les noeuds 'Evenements', * puis appelle pour chacun de ces noeuds des methodes pour * recuperer des informations sur les parametres et sur les * fonctions */ public void addListeEvenements(C_Evenements _listeEvenements){ listeEvenements.addElement(_listeEvenements); } public void removeListeEvenements(C_Evenements _listeEvenements){ listeEvenements.removeElement(_listeEvenements); 24 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » } public void setListeEvenements(Vector _listeEvenements){ listeEvenements=_listeEvenements; } public Vector getListeEvenements(){ return listeEvenements; } public static void traiterDocument() { String nomNode=document.getNodeName(); System.out.println("Type de NODE :"+nomNode); System.out.println("Racine :"+document.getFirstChild().getNodeName()); //****************** niveau 0 : racine ************************** // recherche le noeud principal et traite ses attributs NodeList paramNodeList = document.getElementsByTagName(S_CALENDRIER); traiterCalendrier(paramNodeList.item(0)); //****************** niveau 1 *********************************** // recherche le noeud definissant les événements et on traite ses attributs paramNodeList = document.getElementsByTagName(S_EVTS); for(int i=0; i< paramNodeList.getLength();i++) { Node paramNode = paramNodeList.item(i); // pour chacun de ces noeuds, on fait appel à la méthode traiterEvenements if(DEBUG) System.out.println("Evenements : "+paramNode); traiterEvenements(paramNode); } } /** * noeud principal */ private static void traiterCalendrier(Node Evenements) { } /** * methode qui recupere les attributs du noeud de 1er niveau : evenements * * principe : * - on recupere les attributs du noeud */ private static void traiterEvenements(Node Evenement) { // on recupere les attributs du noeud NamedNodeMap attributes = Evenement.getAttributes(); Node attrEvenements = attributes.getNamedItem(S_EVTS_DATE); if(DEBUG) System.out.println(">>>>>>>>>>>> Date de l'événement : ["+attrEvenements.getNodeValue()+"] <<<<<<<<<<<<"); 25 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » // creation de l'événement et initialisation de la date C_Evenements unEvenement = new C_Evenements(); unEvenement.set_dateEvenement(attrEvenements.getNodeValue()); // ajout dans la liste listeEvenements.addElement(unEvenement); // traitement du noeud defini dans Evenements // recherche le noeud et traite ses attributs NodeList noeudsEvenement = ((Element)Evenement).getElementsByTagName(S_EVT); for(int i=0; i< noeudsEvenement.getLength();i++) { Node paramNode = noeudsEvenement.item(i); // on fait appel à la méthode traiterEvenement traiterEvenement(paramNode, unEvenement); } } /** Methode qui recupere le nom d'un parametre */ private static void traiterEvenement(Node evenement, C_Evenements __evenements) { /* sous une implementation DOM, chaque noeud a un fils "TEXT NODE", c'est ce noeud qui contient la valeur contenue entre les tags */ // on recupere les attributs du noeud NamedNodeMap attributes = evenement.getAttributes(); System.out.println("Nombre d'attributs lus:"+attributes.getLength()); if(attributes.getLength() != I_EVT_NB) { System.out.println("Le document XML n'est pas bien forme"); System.exit(0); } // on recupere les noeuds correspondant aux attributs Node attrType = attributes.getNamedItem(S_EVT_TYPE); Node attrLieu = attributes.getNamedItem(S_EVT_LIEU); Node attrActeurs = attributes.getNamedItem(S_EVT_ACTEURS); if(DEBUG) System.out.println("Evenement :"); if(DEBUG) System.out.println("- Type : "+attrType.getNodeValue()); if(DEBUG) System.out.println("- Lieu : "+attrLieu.getNodeValue()); if(DEBUG) System.out.println("- Acteurs : "+attrActeurs.getNodeValue()); // creation du parametre et ajout dans la liste des parametres de la station courante C_Evenement unEvenement = new C_Evenement(); unEvenement.set_typeEvenement((String)attrType.getNodeValue()); unEvenement.set_lieuEvenement((String)attrLieu.getNodeValue()); unEvenement.set_acteursEvenement((String)attrActeurs.getNodeValue()); __evenements.addListeEvts(unEvenement); } 26 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » /** * cette méthode lit le fichier de donnees dont le nom * est passe en parametre, stocke chaque donnee rencontree * au format 'Double' dans une liste qu'elle retourne */ private static ArrayList lireFichier(String filename) { ArrayList resultat = new ArrayList(); if(DEBUG) System.out.println("Lecture du fichier de donnees"); try { // on cree n flux pour lire le fichier BufferedReader br = new BufferedReader(new FileReader(filename)); String chaine = br.readLine(); while(chaine != null) { if(DEBUG) System.out.println("valeur : "+chaine); chaine.trim(); // les valeurs du fichier sont stockees dans la hashmap sous // forme d'objet Double if(!chaine.equals("")) resultat.add(Double.valueOf(chaine)); chaine = br.readLine(); } } catch(FileNotFoundException fnfe) { System.out.println("Le fichier de donnees n'a pas ete trouve ; le chemin est incorrect"); System.out.println(fnfe + " " +fnfe.getMessage()); } catch(IOException ioe) { System.out.println("Probleme lors de la recuperation des fichiers de donnees"); System.out.println(ioe + " " + ioe.getMessage()); System.exit(0); } return resultat; } } C_Evenements.java package calendrier; /* * generated with velocity template engine * */ import java.util.*; import java.lang.String; public class C_Evenements { //attributes private String _dateEvenement; public void set_dateEvenement(String __dateEvenement){_dateEvenement=__dateEvenement;} public String get_dateEvenement(){return _dateEvenement;} //associations 27 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » public Vector listeEvts=new Vector(); public void addListeEvts(C_Evenement _listeEvts){ listeEvts.addElement(_listeEvts); } public void removeListeEvts(C_Evenement _listeEvts){ listeEvts.removeElement(_listeEvts); } public void setListeEvts(Vector _listeEvts){ listeEvts=_listeEvts; } public Vector getListeEvts(){ return listeEvts; } } C_Evenement.java package calendrier; /* * generated with velocity template engine * */ import java.util.*; import java.lang.String; //import java.lang.Float; public class C_Evenement { //attributes private String _typeEvenement; private String _lieuEvenement; private String _acteursEvenement; public void set_typeEvenement(String __typeEvenement){_typeEvenement=__typeEvenement;} public String get_typeEvenement(){return _typeEvenement;} public void set_lieuEvenement(String __lieuEvenement){_lieuEvenement=__lieuEvenement;} public String get_lieuEvenement(){return _lieuEvenement;} public void set_acteursEvenement(String __acteursEvenement){_acteursEvenement=__acteursEvenement;} public String get_acteursEvenement(){return _acteursEvenement;} //associations } 28 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » ANNEXE 3 1- Analyse des sites http://trad75.free.fr/ Données textuelles présentées sur une ligne ; il existe une logique dans le classement, avec certaines informations facultatives. Pour pouvoir distinguer les différents types d’informations caractérisant un événement, il est nécessaire d’en connaître le sens, car rien dans la structure du document permet de les identifier. Difficilement exploitable Informations : - date (les événements sont classés selon ce critère) type d’événement (bal, concert, stage) adresse (ville – département - arrondissement, rue) heure de déroulement nom du groupe, des intervenants, et toute autre information concernant l’événement prix (en euros ou entrée libre) n° de téléphone (facultatif) adresse e-mail, url (facultatif) Analyse : Il existe une logique dans le classement Les informations fournies concernant un événement sont nombreuses Le calendrier est fourni (10 pages) Le nom des acteurs ne peut pas être distingué des autres informations fournies sans en connaître le sens http://www.bzh5.com/gouel/degemer.php Site réalisé avec PHP. Page structurée. Les informations sont le résultat d’une requête. Elles sont présentées dans un tableau, de manière homogène. Exploitable Recherche dynamique par date, groupe/artiste, lieu Les résultats sont donnés par jour. Chaque date fait partie d’une liste, dont les balises doivent constituer un point de repère. Les informations, pour une date donnée, sont présentées dans un tableau. Chaque ligne décrit un événement. Par ligne, on retrouve 3 informations + 1 colonne permettant d’accéder à un complément d’information. Informations - date - type d’événement (fest-noz, …) - lieu (ville en breton, [département], ville en français) - Acteurs (groupe, artiste) - Détail 29 16/04/17 Projet d’ingénierie « Méta-calendrier automatique pour portail www » Page statique réalisée en HTML. Il n’y a pas d’homogénéité dans la présentation des champs (cela signifie qu’il sera difficile d’extraire l’information minimale utile, étape nécessaire pour détecter les doublons par exemple). La structure en tableau permet cependant de distinguer clairement la nature de l’information. http://www.normandiefolk.com/ normandiefolk/agenda2.htm Exploitable Page statique ; les événements sont classés par mois Les résultats sont donnés par jour. Chaque date fait partie d’une liste, dont les balises doivent constituer un point de repère. Les informations, pour une date donnée, sont présentées dans un tableau. Chaque ligne décrit un événement. Par ligne, on retrouve 4 informations et 1 colonne permettant d’accéder à un complément d’information. Informations - date (pas d’homogénéité dans la présentation de ce champ) - descriptif de l’événement (idem) - lieu - contact - tarif Analyse : Les champs sont remplis individuellement. Il n’y a pas d’homogénéité dans la présentation. 30