(REGEX) Item aus RSS-File in Array speichern
Jeena Paradies
- perl
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
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
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
Moin!
Argh! Kleine Korrekur! Was hab ich da nur für Unfug geschrieben?
my(@items)= ($feed=~ m#<item>(.*?)</item>#g);
-- Skeeve
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
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
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
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
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
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.
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
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
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.
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