![Verwenden von sed zum Filtern von RSS-Elementen](https://rvso.com/image/1605160/Verwenden%20von%20sed%20zum%20Filtern%20von%20RSS-Elementen.png)
Ich möchte ein Skript schreiben, das:
- Nimmt eine RSS-Feed-URL als Eingabe an
- Lädt den Feed herunter
- Löscht alle
<item> ...</item>
Vorkommen, bei denen dastitle
Tag keinem regulären Ausdruck entspricht.
Das folgende Beispiel soll dies verdeutlichen. Nehmen wir an, wir haben einen RSS-Feed mit diesen drei Elementen:
- Projekt Foo – Lasst uns anfangen!
- Etwas ganz anderes
- Ein weiteres Update zu Projekt Foo
Ich möchte nur die Elemente behalten, deren Titel „Projekt Foo“ enthält.
Beispiel-Eingabedatei:
<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
<channel>
<title>My glorious newsfeed</title>
<description>...</description>
<link>...</link>
<language>...</language>
<pubDate>...</pubDate>
<item>
<title>Project Foo - Let's get started!</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
<item>
<title>Something else entirely</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
<item>
<title>Another update on Project Foo</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
</channel>
</rss>
Beispiel-Ausgabedatei:
<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
<channel>
<title>My glorious newsfeed</title>
<description>...</description>
<link>...</link>
<language>...</language>
<pubDate>...</pubDate>
<item>
<title>Project Foo - Let's get started!</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
<item>
<title>Another update on Project Foo</title>
<link>...</link>
<description>...</description>
<pubDate>...</pubDate>
</item>
</channel>
</rss>
Wenn möglich, würde ich gerne auf solche Tools verzichten python
und dies mit Kommandozeilentools tun. Aber ich bin ein absoluter Neuling in der Verwendung von sed
usw. und brauche etwas Hilfe :)
Folgendes habe ich bisher:
cat sample-feed.xml \
| tr -d '\n' \
| sed $'s/\<item\>/\\\n\<item\>/g;s/\<\/channel\><\/rss\>/\\\n\<\/channel\><\/rss\>/g' \
| sed '/^\<item\>/ d'
Zuerst lösche ich alle Zeilenumbrüche. Dann füge ich Zeilenumbrüche hinzu, um jeden <item>...</item>
in eine eigene Zeile zu bringen. Der letzte Befehl löscht alle Zeilen, die mit beginnen <item>
. Für
Das Ergebnis ist ein gültiger RSS-Feed ohne Elemente:
<?xml version="1.0" encoding="iso-8859-1"?><rss version="2.0"><channel><title>My glorious newsfeed</title><description>...</description><link>...</link><language>...</language><pubDate>...</pubDate>
</channel></rss>
Damit dies mit URLs statt mit lokalen Dateien funktioniert, würde ich einfach durch cat sample-feed.xml
ersetzen curl -s <some url>
.
Was allerdings noch fehlt, ist eine Modifikation des Befehls sed '/^\<item\>/ d'
, die nur Zeilen löscht, die mit „Project Foo“ beginnen, <item>
aber nicht enthalten.
Wenn Sie mir also helfen könnten, herauszufinden, was die letzte Zeile enthalten soll, wäre ich sehr glücklich. Andererseits bin ich sicher, dass es eine elegantere Möglichkeit gibt, dies zu tun. Soweit ich gesehen habe, sed
ist es ziemlich leistungsfähig und es sollte möglich sein, dies mit einem sed
Befehl zu tun.
Ich freue mich auf eure Antworten :-)
Antwort1
Wie in den Kommentaren vorgeschlagen, habe ich versucht, xmlstarlet
dieses Problem zu lösen, und es funktioniert gut. Hier ist mein Skript
xml ed -d '//item[not(contains(title,"Project Foo"))]' < sample_rss.xml
Nehmen wir an, der Feed-Inhalt befindet sich in der Datei sample_rss.xml
. Dieser Inhalt wird in eingespeist xml ed -d
, wodurch alle Notizen gelöscht werden, die dem angegebenen XPath-Ausdruck entsprechen. Der XPath-Ausdruck sucht nach allen <item>
, die keinen Knoten haben <title>
, der den Text enthält "Project Foo"
.
Dies scheint gut zu funktionieren und ich bin auch mit der Ausführungszeit sehr zufrieden:
real 0m0.003s
user 0m0.001s
sys 0m0.002s
Vorsicht bei Namespaces
Wenn Sie dies mit richtigen RSS- oder Atom-Feeds zum Laufen bringen möchten, bemerken Sie möglicherweise, dass es feed
ein XML-Namespace- xmlns
Attribut () enthält, genau wie in diesem Beispiel von YouTube:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015" xmlns:media="http://search.yahoo.com/mrss/" xmlns="http://www.w3.org/2005/Atom">
...
</feed>
Dann funktioniert das obige Skript nicht mehr! Es hat mir ziemliche Kopfschmerzen bereitet, es zu reparieren, aber so kann ich es wieder zum Laufen bringen:
xml ed -d '//_:entry[not(contains(_:title,"Project Foo"))]' < youtube_rss.xml
Mehr zu diesem Namespace-Problem hier:http://xmlstar.sourceforge.net/doc/UG/ch05.html