2010-06-03 4 views
1

Je suis juste un débutant en perl, et j'ai besoin de toute urgence de préparer un petit script qui prend les trois premières choses à partir d'un fichier xml et les place dans un nouveau. Voici un exemple d'un fichier xml:Analyse du fichier XML avec perl - regex

<article> 
    {lot of other stuff here} 
</article> 
<article> 
    {lot of other stuff here} 
</article> 
<article> 
    {lot of other stuff here} 
</article> 
<article> 
    {lot of other stuff here} 
</article> 

Ce que je voudrais faire est d'obtenir 3 premiers articles ainsi que toutes les balises entre les deux et le mettre dans un autre fichier. Merci pour toute l'aide à l'avance ce qui concerne peter

+0

duplication possible de [Comment utiliser les expressions régulières Perl pour analyser des données XML?] (Http://stackoverflow.com/questions/2950661/how-can-i-use-perl-regular-expressions-to-parse -xml-data) – Quentin

+0

@SMark: Même si. - Les expressions rationnelles Perl6 sont * toujours * le mauvais outil pour cela. ;-) – Tomalak

Répondre

12

Never ever use Regex to handle markup languages.

La version originale de cette réponse (voir ci-dessous) utilisés XML::XPath. Grant McLean a dit dans les commentaires:

XML::XPath est un module ancien et unmaintained. XML::LibXML est un module moderne, maintenu avec une API presque identique et c'est aussi plus rapide.

donc je fait une nouvelle version qui utilise XML::LibXML (merci, Grant):

use warnings; 
use strict; 
use XML::LibXML; 

my $doc = XML::LibXML->load_xml(location => 'articles.xml'); 
my $xp = XML::LibXML::XPathContext->new($doc->documentElement); 
my $xpath = '/articles/article[position() < 4]'; 

foreach my $article ($xp->findnodes($xpath)) { 
    # now do something with $article 
    print $article.": ".$article->getName."\n"; 
} 

Pour moi cette impression:

 
XML::LibXML::Element=SCALAR(0x346ef90): article 
XML::LibXML::Element=SCALAR(0x346ef30): article 
XML::LibXML::Element=SCALAR(0x346efa8): article 

Liens vers la documentation pertinente:


La version originale de la réponse, sur la base du paquet XML::XPath:

use warnings; 
use strict; 
use XML::XPath; 

my $xp = XML::XPath->new(filename => 'articles.xml'); 
my $xpath = '/articles/article[position() < 4]'; 

foreach my $article ($xp->findnodes($xpath)->get_nodelist) { 
    # now do something with $article 
    print $article.": ".$article->getName ."\n"; 
} 

qui imprime pour moi:

 
XML::XPath::Node::Element=REF(0x38067b8): article 
XML::XPath::Node::Element=REF(0x38097e8): article 
XML::XPath::Node::Element=REF(0x3809ae8): article 
+1

C'est un cas où une regex pourrait facilement faire le travail cependant. –

+5

@Snake Plissken: Non, ce n'est pas le cas. Regex n'est * jamais * le bon outil pour ce genre de travail, peu importe sa facilité. XPath + Langage de programmation X (Perl dans ce cas) est, ou XSLT est. Regex ne l'est pas. – Tomalak

+0

Vous êtes stupide. Dans ce cas, une regex peut facilement faire le travail. Qu'allez-vous faire dans le cas où quelqu'un vous demande de copier un fichier non-XML jusqu'à ce que quelque chose a été vu trois fois? –

0

ici:

open my $input, "<", "file.xml" or die $!; 
open my $output, ">", "truncated-file.xml" or die $!; 
my $n_articles = 0; 
while (<$input>) { 
     print $output $_; 
     if (m:</article>:) { 
      $n_articles++; 
      if ($n_articles >= 3) { 
       last; 
      } 
     } 
}   
close $input or die $!; 
close $output or die $!; 

Vous vraiment ne pas besoin d'un analyseur XML pour faire un travail simple.

+0

Qu'est-ce que ce script a fait est-il copié tout le contenu du fichier.xml dans truncated-file.xml – dusker

+0

Ensuite, c'est le temps de débogage pour vous. Quoi qu'il en soit, il y a une autre réponse que vous pouvez utiliser si cela ne fonctionne pas. –

+0

Pourriez-vous partager cette autre solution? merci – dusker