Eu gostaria de escrever um script que:
- Recebe algum URL do feed RSS como entrada
- Baixa o feed
- Exclui todas
<item> ...</item>
as ocorrências onde atitle
tag não corresponde a alguma expressão regular.
O exemplo a seguir deve ilustrar isso. Digamos que temos um RSS Feed com estes três itens:
- Projeto Foo - Vamos começar!
- Algo totalmente diferente
- Outra atualização no Projeto Foo
Quero manter apenas os itens que possuem "Projeto Foo" no título.
Exemplo de arquivo de entrada:
<?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>
Exemplo de arquivo de saída:
<?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>
Se possível, gostaria de ficar longe de coisas assim python
e fazer isso com ferramentas de linha de comando. Mas sou um grande novato no uso de sed
etc. e preciso de ajuda :)
Aqui está o que tenho até agora:
cat sample-feed.xml \
| tr -d '\n' \
| sed $'s/\<item\>/\\\n\<item\>/g;s/\<\/channel\><\/rss\>/\\\n\<\/channel\><\/rss\>/g' \
| sed '/^\<item\>/ d'
Primeiro, excluo todas as novas linhas. Em seguida, adiciono novas linhas para colocar cada uma <item>...</item>
em sua própria linha. O comando final até agora exclui todas as linhas que começam com <item>
. Para
O resultado é um feed rss válido sem nenhum item:
<?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>
Para fazer isso funcionar com URLs em vez de arquivos locais, eu apenas substituiria cat sample-feed.xml
por curl -s <some url>
.
O que ainda falta é uma modificação no comando sed '/^\<item\>/ d'
que exclui apenas as linhas que começam com, <item>
mas não contêm, "Project Foo".
Então, se você pudesse me ajudar a descobrir o que a última linha deveria dizer, eu ficaria muito feliz. Por outro lado, tenho certeza de que existe uma maneira mais elegante de fazer isso. Pelo que vi sed
é bastante poderoso e deve ser possível fazer isso com um sed
comando.
Aguardo suas respostas :-)
Responder1
Conforme sugerido nos comentários, tentei usar xmlstarlet
para resolver isso e funcionou bem. Aqui está meu roteiro
xml ed -d '//item[not(contains(title,"Project Foo"))]' < sample_rss.xml
Vamos supor que o conteúdo do feed esteja no arquivo sample_rss.xml
. Esse conteúdo é alimentado xml ed -d
, o que exclui qualquer nota que corresponda à expressão XPath fornecida. A expressão XPath procura qualquer um <item>
que não possua um nó <title>
que contenha o texto "Project Foo"
.
Isso parece funcionar bem e também estou muito feliz com o tempo de execução:
real 0m0.003s
user 0m0.001s
sys 0m0.002s
Cuidado com os namespaces
Se você quiser fazer isso funcionar com feeds rss ou atom adequados, você pode notar que feed
contém um atributo XML Namespace ( xmlns
), assim como neste exemplo do 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>
Então, o script acima não funcionará mais! Me causou muita dor de cabeça consertar isso, mas aqui está como fazer funcionar:
xml ed -d '//_:entry[not(contains(_:title,"Project Foo"))]' < youtube_rss.xml
Mais sobre esse problema de namespace aqui:http://xmlstar.sourceforge.net/doc/UG/ch05.html