sed を使用して RSS アイテムをフィルタリングする

sed を使用して RSS アイテムをフィルタリングする

次のようなスクリプトを書きたいと思います:

  • RSSフィードURLを入力として受け取ります
  • フィードをダウンロードする
  • タグが正規表現と一致しないすべての<item> ...</item>出現を削除します。title

次の例でこれを説明します。次の 3 つの項目を含む RSS フィードがあるとします。

  • Project Foo - 始めましょう!
  • まったく別のもの
  • Project Fooの最新情報

タイトルに「Project Foo」が含まれるアイテムのみを保持したいと思います。

入力ファイルの例:

<?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>

出力ファイルの例:

<?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>

可能であれば、 のようなツールは使わずにpython、コマンドライン ツールで実行したいのですが、私はsedなどの使用にまったく慣れていないので、助けが必要です :)

これまでのところ、次のものがあります:

cat sample-feed.xml \
  | tr -d '\n' \
  | sed $'s/\<item\>/\\\n\<item\>/g;s/\<\/channel\><\/rss\>/\\\n\<\/channel\><\/rss\>/g' \
  | sed '/^\<item\>/ d'

まず、改行をすべて削除します。次に、改行を追加して、各行を<item>...</item>独自の行にします。最後のコマンドは、で始まるすべての行を削除します<item>

結果は、アイテムのない有効な RSS フィードになります。

<?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>

これをローカル ファイルではなく URL で動作させるには、cat sample-feed.xmlを に置き換えるだけですcurl -s <some url>

ただし、まだ不足しているのは、「Project Foo」で始まるが「Project Foo」を含まないsed '/^\<item\>/ d'行のみを削除するコマンドの変更です。<item>

したがって、最後の行に何を書くべきかを教えていただければ、とてもうれしいです。一方で、これを行うにはもっとエレガントな方法があるはずです。私が見た限りでは、これは非常に強力で、1 つのコマンドsedで実行できるはずです。sed

回答をお待ちしています:-)

答え1

コメントで提案されているように、xmlstarletこれを解決するために使用してみましたが、うまくいきました。これが私のスクリプトです

xml ed -d '//item[not(contains(title,"Project Foo"))]' < sample_rss.xml

フィード コンテンツがファイル にあると仮定しますsample_rss.xml。そのコンテンツは にフィードされ、指定された XPath 式に一致するすべてのメモが削除されます。XPath 式は、テキスト を含む ノードを持たない をxml ed -d検索します。<item><title>"Project Foo"

これはうまく機能しているようで、実行時間にも非常に満足しています。

real    0m0.003s
user    0m0.001s
sys     0m0.002s

名前空間に注意

これを適切な RSS フィードまたは Atom フィードで動作させたい場合、 YouTube の次の例のように、feedに XML 名前空間 ( ) 属性が含まれていることに気付くでしょう。xmlns

<?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>

そうすると、上記のスクリプトは動作しなくなります。これを修正するのにかなり頭を悩ませましたが、動作させる方法は次のとおりです。

xml ed -d '//_:entry[not(contains(_:title,"Project Foo"))]' < youtube_rss.xml

この名前空間の問題の詳細については、こちらをご覧ください。http://xmlstar.sourceforge.net/doc/UG/ch05.html

関連情報