IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

Traitement imbrication (x)html & désambiguïsation de balises fermantes


Sujet :

Langage Perl

  1. #1
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 2
    Points : 1
    Points
    1
    Par défaut Traitement imbrication (x)html & désambiguïsation de balises fermantes
    Bonjour à tous (1er post \o/)

    d'habitude j'arrive (à peu près & tant bien que mal) à me débrouiller tout seul, mais la je sèche, alors je viens crier au secours
    je vais essayer de décrire le mieux possible comment se comporte mon corpus.

    je travail sur des fichiers xhtml de textes de loi en diachronie afin d'en étudier les variations... bref, je vous passe certains détails. Mais ceux ci vous aideront peut être pour me guider !

    1 ) Ces fichiers sont structurés avec pleins de <div> imbriquées dont l'ouvrante porte un attribut renseignant sur sa place dans la hierarchie.
    code > livres > parties > chapitrse > sections > sous sections > paragraphes > sous paragraphes > articles... (la liste est non exhaustive et non finie...)

    bref, un code contenant des livres contenant eux même des chapitres... blablabla

    2 ) tous les niveaux de hiérarchie ne sont pas présents obligatoirement.
    (Dans un livre on peut arriver directement sur des articles).

    3 ) dans un script perl (autre que celui que je vous ai mis) je parse ces <div> à base de regexp mais vous imaginez la taille des regexp.. qui me sortent une "segmentation fault" quand les fichiers commencent à dépasser 4 ou 5 Mo (mais peut être ce n'est pas du à leur taille mais à leur structure). SI c'est du à leur taille, y'a ptete moyen d'augmenter la taille de la pile qui doit ptete merde du fait de la complexité de la regexp.

    Bref, dans mes regexp, quand je veux matcher un élement de type <div attr="..."> ... </div> (qui contient lui même des div à la pelle) je suis obligé de détailler l'intérieur avec les div que je peux rencontrer (ou pas, donc y'a plein de * ou/et de ? imbriqués) afin de matcher la bonne </div> fermante. Ptete pour ça que ça plante !
    bref, traitement très lourd, et peut être très stupide.

    4 ) je me suis donc dit : "tiens, vais essayer de pré-traiter le xml histoire de faciliter la vie à mon script derrière".

    j'ai donc essayé de créer une routine (voir tout en bas) qui pour une div ouvrante donnée va récupérer la fermante, et remplacer le div par l'attribut
    donc au lieu d'avoir ça
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <div attr="chapitre">
    <div attr="article">...</div>
    <div attr="article">...</div>
    </div>

    j'ai ça
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <chapitre>
    <article>...</article>
    <article>...</article>
    </chapitre>
    ce qui permet de désambiguïser mes </div> et de pouvoir matcher mes éléments de cette manière
    Code perl : Sélectionner tout - Visualiser dans une fenêtre à part
    $pattern="<chapitre>.*?</chapitre>"

    mais ça marche pas. ça me renvoie toujours sur le
    Code perl : Sélectionner tout - Visualiser dans une fenêtre à part
    return "Pb d'imbrication pour la balise div\n";
    bien que le fichier soit valide xhtml.

    5 ) je suis sous mac OSX

    6 ) quelqu'un a une idée / piste de comment je pourrais m'y prendre ?
    je dois me pendre ? Y'a un module qui ferait ça ? Dois je plutot partir sur du XLS pour faire mes transformations ? Bref, vous l'aurez compris, je suis un peu perdu, excusez mon amateurisme.

    Merci encore, si vous avez besoin de plus de précisions, n'hésitez pas ,)

    Code perl : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    use locale;
    open(IN,"<","index.html");
    while($line=<IN>){
    	$doc.=$line;
    }
     
    open(OUT,">","out.xml");
    print OUT parseFirstTag($doc);
    close(IN);close(OUT);
     
    sub parseFirstTag {
    	my $text=shift;
    	if ($text=~/^(.*?)<div\s?[^>]*?><h\d><a[^>]*?>([^ ]*?) ([^<]*?)<\/a><\/h\d>(.*)/si) {
    			my $avantTag=$1; 		# on enregistre ce qui précède
    			my $type=$2;
    			my $id=$3;
    			my $apresTag=$4; 		# on enregistre ce qui suit
    			my $content="";
    			my $resteAFermer=1;		# on enregistre le nombre de balises fermantes qu'il va falloir trouver dans la suite
    			# tant qu'il reste des balises fermantes </tag> à trouver
    			while ($resteAFermer>0) {
    				# on recherche dans la suite la première occurrence de balise fermante
    				if ($apresTag=~/^(.*?)(<\/div>)(.*)/i) {
    					my $avant=$1;									# on enregistre ce qui précède cette fermante (dans la suite)
    					my $fermante=$2;
    					$content.=$avant.$fermante;
    					$apresTag=$3;									# on met à jour la suite à analyser
    					my $compteOuvrantes=($avant=~/<div[^>]*>/gi);	# on compte le nombre de balises ouvrantes présentes dans ce qui précède la fermante
    					$resteAFermer = $resteAFermer - 1 + $compteOuvrantes;	# on met à jour le nombre de fermante à trouver dans la suite ( -1 car on vient d'en trouver une +compteOuvrante pour toutes celles qu'on vient d'ouvrir) 
    				} 
    				else {
    					# si on ne trouve pas de fermante, c'est qu'il y a un problème de codage xml
    					return "Pb d'imbrication pour la balise div\n";
    					$resteAFermer=-1; # on force la sortie
    				}
    			}
    			# si on est sorti de la boucle correctement, en trouvant la dernière fermante, on effectue la suppression en réaffectant $text
    			if ($resteAFermer==0) {
    				$content=~/^(.*)<\/div>$/;
    				$content=$1;
    				$text=$avantTag."<".$type." id=\"".$id."\">".$content."</".$type.">".$apresTag;
    			}
    	}
    	return $text;	
    }

    Puis pour les amateurs d'xkcd (et de segfault) comme moi :p

  2. #2
    Membre confirmé Avatar de iblis
    Inscrit en
    Janvier 2007
    Messages
    510
    Détails du profil
    Informations personnelles :
    Âge : 57

    Informations forums :
    Inscription : Janvier 2007
    Messages : 510
    Points : 570
    Points
    570
    Par défaut
    La présence de balises imbriquées suffit à elle seule pour voir que ce n'est pas du ressort des expressions régulières. Même si le moteur regex des versions récentes de Perl a des fonctionnalités avancées permettant de traiter, par exemple, le balancement de balises ouvrantes et fermantes, ce n'est pas fait pour ça.

    Utilise un vrai parseur XHTML. Tu as le choix sur le CPAN.

    Selon tes besoins, par exemple s'il s'agit plus de reformater, de produire de nouveaux fichers structurés que de faire du data mining, XSLT peut aussi être une bonne solution.

    Si tu jettes un oeil aux modules de parseurs XML et XHTML, tu verras qu'il y a en gros deux approches, en gros évènements et arbres .

    Je te conseille XML::Twig qui permet les deux approches, peut traiter de très gros fichier (en ne chargeant en mémoire que ce dont tu as besoin), s'interface avec XML::LibXML pour de meilleures performances et a une excellente documentation. C'est mon outil de choix mais à toi de voir ce que tu préfères (il y a plusieurs fils sur le forum Perl qui discutent ces modules, regarde aussi la FAQ).

    Attention XML::Twig, comme tous les parseurs XML du CPAN d'après mon expérience, demande du XML (ou XHTML) bien formé. Ce n'est pas toujours le cas du HTML du Web. Donc là, il peut être utile de parser d'abord avec un parseur HTML (dans ton cas plutôt HTML::Parser que HTML::TreeBuilder) et de produire un XML qui répond à tes besoins.

    Mais vraiment laisse les expressions régulières de côté pour l'extraction de données complexes de fichiers XHTML. (Le problème avec ta regex vient des *? mais je ne veux pas m'étendre dessus car ce n'est pas la bonne solution à mon avis).

  3. #3
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 2
    Points : 1
    Points
    1
    Par défaut
    Merci bien.
    je ne suis pas trop familier des modules, mais c'est l'occasion de faire joujou avec

    Merci à toi !

  4. #4
    Rédactrice

    Avatar de stoyak
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    408
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2005
    Messages : 408
    Points : 1 491
    Points
    1 491
    Cela demande du courage d'en tirer du plaisir
    Quand on n'a qu'un marteau, tous les problèmes ressemblent à un clou

Discussions similaires

  1. Traitement des tableaux de word avec VBA: balise index
    Par Invité dans le forum VBA Word
    Réponses: 20
    Dernier message: 29/11/2005, 15h39
  2. [HTML] Problème avec la balise <mailto>
    Par Taylor² dans le forum Balisage (X)HTML et validation W3C
    Réponses: 8
    Dernier message: 10/10/2005, 16h36
  3. [HTML] [CSS] href et balise img.
    Par Devil666 dans le forum Mise en page CSS
    Réponses: 5
    Dernier message: 15/06/2005, 17h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo