Jeena Paradies: (REGEX) Item aus RSS-File in Array speichern

Hallo,

Ich habe ein RSS-File als String:

my $feed = "  
<chanel>  
 <item>  
  foo  
 </item>  
 <item>  
  bar  
 </item>  
</chanel>  
";

Jetzt hätte ich gerne die Inhalte der einzelnen items in einem Array:

my @items = ("foo", "bar");

Aber ich bekomme das leider schon seit über 7 Stunden nicht hin. Mein Ansatz war das ganze mit einem einfachen Regex zu machen, aber da ich irgendwie keine Ahnung von Perl habe weiß ich nicht wie ich das umsetzen soll, bisher bin ich so weit:

my @items = split(/<item>(.*)<\/item>/g, $feed);  
my $count = @items;  
print $count;

Das ergibt aber immer nur 1 und ich weiß nicht warum :-(

Grüße
Jeena Paradies

  1. MUSS das so komplex sein? versuch es mit explode(), wenn die RSS-Struktur IMMER gleich ist.Entsprechende Array-indexe festzulegen wäre nicht schwer.

    MFG
    bleicher

    --
    __________________________-
    Menschen an sich , sind nicht schlecht - es sind nur ihre Taten (c).
    Lieber bereuen gesündigt zu haben, als nicht sündigen und es später trotzdem bereuen.
    Boccaccio
    1. gudn tach!

      versuch es mit explode() [...]

      nur fuers archiv: kaese! ;-)
      (perl!=php)

      prost
      seth

  2. Moin!

    1. my(@items)= split(/<item>(.*)<\/item>/g, $feed);
    2. Du solltest für sowas auf ein Modul wie (z.B.) XML::Twig aufsetzen

    -- Skeeve

    1. Moin!

      Argh! Kleine Korrekur! Was hab ich da nur für Unfug geschrieben?

      my(@items)= ($feed=~ m#<item>(.*?)</item>#g);

      -- Skeeve

      1. gudn tach!

        Argh! Kleine Korrekur! Was hab ich da nur für Unfug geschrieben?

        das schon, aber es ginge afais auch mit split:

        my @items = split(/<\/?item>/, $feed);

        und dann jedes zweite element. ;-)

        prost
        seth

        1. Moin!

          gudn tach!

          Argh! Kleine Korrekur! Was hab ich da nur für Unfug geschrieben?

          das schon, aber es ginge afais auch mit split:

          Ist alles Blödsinn, da Zeilenumbrüche drin sind!

          Es bleibt dabei: XML::Twig (o.ä.) ist hier das Mittel der Wahl. Ansonsten sowas hier:

          #!/usr/bin/perl  
          use strict;  
          use warnings;  
            
          use Data::Dumper;  
            
          my $feed = "  
          <chanel>  
           <item>  
            foo  
           </item>  
           <item>  
            bar  
           </item>  
          </chanel>  
          ";  
          $feed=~ s/[\012\015]+/ /g;  
          my $odd= 1;  
          my (@items)= grep $odd=1-$odd,split m#<item>(.*?)</item>#m, $feed;  
            
          print Dumper \@items;
          

          -- Skeeve

          1. gudn tach!

            Argh! Kleine Korrekur! Was hab ich da nur für Unfug geschrieben?

            das schon, aber es ginge afais auch mit split:
            Ist alles Blödsinn, da Zeilenumbrüche drin sind!

            hihi, wir sind dumm!

            Es bleibt dabei: XML::Twig (o.ä.) ist hier das Mittel der Wahl.

            ack

            Ansonsten sowas hier: [...]
            $feed=~ s/[\012\015]+/ /g;
            my $odd= 1;
            my (@items)= grep $odd=1-$odd,split m#<item>(.*?)</item>#m, $feed;

            geil!

            aber der m-modifier ist doch hier ueberfluessig, oder?

            prost
            seth

  3. Moin!

    So geht's (z.B.) mit XML::Twig:

    #!/usr/bin/perl  
      
    use strict;  
    use warnings;  
      
    use Data::Dumper;  
    use XML::Twig;  
      
    ###### TWIG ################################################################{{{  
    my $rss= new XML::Twig(  
     twig_handlers => {  
      item => \&item,  
     },  
    );  
    ###### END: TWIG ###########################################################}}}  
      
    my @items;  
      
    my $feed = "  
    <chanel>  
     <item>  
      foo  
     </item>  
     <item>  
      bar  
     </item>  
    </chanel>  
    ";  
      
    $rss->parse($feed);  
      
    print Dumper \@items;  
      
    sub item {  
     my( $t, $elt )= @_;  
     push @items, $elt->text();  
    }
    

    -- Skeeve

  4. Hallo,

    Vielen dank euch allen für die Hilfe, jetzt ist im endeffekt so etwas daraus geworden:

     if(open($old_feed, "<$options{'feed'}")) {  
      while(<$old_feed>) {  
       $old_items .= $_;  
      }  
      my @old_items = ($old_items =~ /<item>.*?<\/item>/sg);  
      for(my $i = 0; $i < @old_items; $i++) {  
       if(@old_items[$i] =~ /<guid isPermaLink="false">dailystrip-$short_date<\/guid>/sg) {  
        delete @old_items[$i];  
       }  
      }  
      if(@old_items > 14) {  
       pop(@old_items);  
      }  
      $old_items = "  " . join("  \n  ", @old_items);  
      close($old_feed);  
     }
    

    Und das funktioniert auch prima :-)

    Wenn jetzt jemand noch Lust hätte die Feed-Funktionalität des dailystrips zu überprüfen, ich habe das veränderte Paket, auf meinem Webspace temporär hochgeladen:

    http://jeenaparadies.net/t/self/dailystrips-1.1.0.tar.gz

    um sich auch einen Feed erstellen zu lassen ruft man das ganze dann so auf:

    tux:~ jeena$ dailystrips userfriendly dilbert --feed /pfad/zu/daily-feed.xml

    Wenn das so alles fehlerfrei funktioniert werde ich die Änderungen dem Orginalautor zukommen lassen und hoffe dass er das dann auch übernimmt. Wenn nicht dann werde ich das wohl unter einem anderen Namen bei mir irgendwo veröffentlichen müssen (GPL erlaubt das ja).

    Da das meine ersten gehversuche mit Perl überhaupt sind kann ich mir nicht sicher sein, dass das auch alles so funktioniert wie ich mir das gedacht habe, auch wenn ich es ausgiebig getestet habe ;-).

    Grüße
    Jeena Paradies

    1. Vielen dank euch allen für die Hilfe, jetzt ist im endeffekt so etwas daraus geworden:

      [code lang=perl] if(open($old_feed, "<$options{'feed'}")) {
        while(<$old_feed>) {

      Filehandles sind keine Skalare, ausserdem ist es usus auch Systemoperationen zu checken.

      if( open (FH , "<$options{feed}") ) {
         while(<FH>) { ....

      } else {
       warn "Fehler beim öffnen von $options{feed}: $!";
      }

      Aber!
      wie Skeeve schon sagte, ist es durchaus üblich in Perl, dafür fertige Module von CPAN zu benutzen, gerade zu XML sollten Reihenweise Module verfügbar sein. Zumal so ein Geschichte (das Parsen von XML) schnell ausartet.

      $old_items .= $_;
        }
        my @old_items = ($old_items =~ /<item>.*?</item>/sg);

      schon allein das sollte eigentlich nicht funktionieren. Der ausdruck .* sucht alle Zeichen, was jetzt genau das ungierige Fragezeichen da macht weiß ich nicht. Aber um solche Tags zu suchen ist eher so ein Ausdruck üblicher:

      my @erg = ($text =~ /<tag[^>]*>([^<]*)/gi);

      Aber wie gesagt, Module sind immer erste Wahl.

      Struppi.

      --
      Javascript ist toll (Perl auch!)
      1. Moin!

        Filehandles sind keine Skalare, ausserdem ist es usus auch Systemoperationen zu checken.

        Psstt! Struppi! Hast Du auch mit Perl 4 angefangen und kannst Dich nicht so recht davon losreißen? Du kannst inzwischen Skalare für Filehandles verwenden. Ist IIRC auch der "preferred Way".

        schon allein das sollte eigentlich nicht funktionieren. Der ausdruck .* sucht alle Zeichen, was jetzt genau das ungierige Fragezeichen da macht weiß ich nicht.

        Der macht das Sternchen "non greedy". Damit wird also nur bis tum ersten </item> gefunden. Ist also duchaus machbar.

        Aber um solche Tags zu suchen ist eher so ein Ausdruck üblicher:

        my @erg = ($text =~ /<tag[^>]*>([^<]*)/gi);

        98% ack.
        2%: my @erg = ($text =~ m#<tag\b[^>]*>([^<]*)</tag>#g);
        1. \b damit nicht <tage> als <tag> gewertet wird
        2. normalerweise für XML kein "i" da <Tag> != <tag>. Da es hier RSS ist, könntest Du mit dem "i" aber recht haben. Ich kenne RSS nicht genau (und bin zu faul nachzusehen).

        -- Skeeve

      2. Hallo,

        if( open (FH , "<$options{feed}") ) {
           while(<FH>) { ....

        } else {
        warn "Fehler beim öffnen von $options{feed}: $!";
        }

        Ähm dass da keine Datei ist, ist ja kein Fehler sondern der Normalzustand am Anfang.

        wie Skeeve schon sagte, ist es durchaus üblich in Perl, dafür fertige Module von CPAN zu benutzen, gerade zu XML sollten Reihenweise Module verfügbar sein. Zumal so ein Geschichte (das Parsen von XML) schnell ausartet.

        Naja, da ich zu jedem Zeitpunkt zu 100% sicher sein kann wie die Datei aussieht weil ich sie ja selbst 10 Zeilen später erstelle denke ich dass man da auch mal pragmatisch sein und auf relativ einfache regexe, die zur Grunfunktionalität der Sprache gehören setzen kann, anstatt noch künstlich eine zusätzliche Bariere/Abhängigkeit eines Modules herbeizuführen.

        Aber wie gesagt, Module sind immer erste Wahl.

        Was konkret in diesem Fall würde denn eine zusätzliche Abhängigkeit eines Moduls rechtfertigen?

        Grüße
        Jeena Paradies

        1. if( open (FH , "<$options{feed}") ) {
             while(<FH>) { ....

          } else {
          warn "Fehler beim öffnen von $options{feed}: $!";
          }
          Ähm dass da keine Datei ist, ist ja kein Fehler sondern der Normalzustand am Anfang.

          D.h. du möchtest egal welchen Fehler es gibt, dir den nicht anzeigen lassen, weil die Datei am Anfang nicht existiert?
          Um auf die Existenz einer Datei zu testen kannst du -s oder -e benutzen.

          wie Skeeve schon sagte, ist es durchaus üblich in Perl, dafür fertige Module von CPAN zu benutzen, gerade zu XML sollten Reihenweise Module verfügbar sein. Zumal so ein Geschichte (das Parsen von XML) schnell ausartet.
          Naja, da ich zu jedem Zeitpunkt zu 100% sicher sein kann wie die Datei aussieht weil ich sie ja selbst 10 Zeilen später erstelle denke ich dass man da auch mal pragmatisch sein und auf relativ einfache regexe, die zur Grunfunktionalität der Sprache gehören setzen kann, anstatt noch künstlich eine zusätzliche Bariere/Abhängigkeit eines Modules herbeizuführen.

          Module sind das A und O bei Perl. Wenn du darauf verzichten möchtest, dass es Leute gibt die jahrelanger Erfahrung mit Perl oder einer bestimmten Materie haben und diese dir zu Verfügung stellen, dann ist das natürlich eine Möglichkeit, aber gerade als Anfänger wäre es ratsam, zumal der Umgang mit Modulen eine wichtige Fähigkeit ist, die man sich schnell aneignen sollte.

          Aber wie gesagt, Module sind immer erste Wahl.
          Was konkret in diesem Fall würde denn eine zusätzliche Abhängigkeit eines Moduls rechtfertigen?

          * Zuverlässigkeit
          * Erweiterbarkeit
          * weniger und lesbarer Code
          * leichter zu debuggen, da die Module i.d.R. Fehlerprüfungen eingebaut haben.

          Struppi.

          --
          Javascript ist toll (Perl auch!)
        2. Hell-O!

          Aber wie gesagt, Module sind immer erste Wahl.
          Was konkret in diesem Fall würde denn eine zusätzliche Abhängigkeit eines Moduls rechtfertigen?

          Ein paar Gründe hat dir Struppi schon genannt, aber mal als Denkansatz (man muss das Rad ja nicht neu erfinden ;-) ):

          use [link:http://search.cpan.org/~grantm/XML-Simple-2.16/lib/XML/Simple.pm@title=XML::Simple];  
          use [link:http://perldoc.perl.org/IO/File.html@title=IO::File];  
          use Data::Dumper;  
            
          my $fh = IO::File->new('/pfad/zum.xml');  
          my $ref = XMLin($fh);  
          # Kontrollausgabe aller items  
          print Dumper($ref->{channel}->{item});
          

          In $ref hast du einen Zeiger auf dein geparstes XML (die Grundstruktur ist auf der verlinkten Seite beschrieben, ebenso wie die Möglichkeiten der Gruppierung von Einträgen). Das kannst du jetzt noch sortieren und wegschreiben, das war's.

          Siechfred

          --
          Ich bin strenggenommen auch nur interessierter Laie. (molily)
          Siechfreds Tagebuch || Falle Aufteilungsbescheid || RT 221 Erfurt-Altstadt i.V.