Usando sed para filtrar elementos RSS

Usando sed para filtrar elementos RSS

Me gustaría escribir un guión que:

  • Toma alguna URL de fuente RSS como entrada
  • Descarga el feed
  • Elimina todas <item> ...</item>las apariciones en las que la titleetiqueta no coincide con alguna expresión regular.

El siguiente ejemplo debería ilustrar esto. Digamos que tenemos un feed RSS con estos tres elementos:

  • Proyecto Foo - ¡Empecemos!
  • Algo completamente diferente
  • Otra actualización sobre el Proyecto Foo

Quiero conservar sólo aquellos elementos que tengan "Proyecto Foo" en su título.

Archivo de entrada de ejemplo:

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

Archivo de salida de ejemplo:

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

Si es posible, me gustaría alejarme de herramientas como pythony hacer esto con herramientas de línea de comandos. Pero soy un gran novato en el uso sed, etc. y necesito ayuda :)

Esto es lo que tengo hasta ahora:

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

Primero, elimino todas las nuevas líneas. Luego, agrego nuevas líneas para que cada una tenga <item>...</item>su propia línea. El comando final hasta ahora elimina todas las líneas que comienzan con <item>. Para

El resultado es un feed rss válido sin ningún elemento:

<?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 que esto funcione con URL en lugar de archivos locales, simplemente reemplazaría el cat sample-feed.xmlarchivo con curl -s <some url>.

Sin embargo, lo que aún falta es una modificación del comando sed '/^\<item\>/ d'que solo elimina las líneas que comienzan con <item>"Project Foo" pero que no contienen.

Entonces, si pudieras ayudarme a descubrir qué debería decir la última línea, sería muy feliz. Por otro lado, estoy seguro de que existe una forma más elegante de hacerlo. Por lo que he visto, sedes bastante poderoso y debería ser posible hacer esto con un solo sedcomando.

Mirando hacia adelante a sus respuestas :-)

Respuesta1

Como se sugiere en los comentarios, intenté usar xmlstarletpara resolver esto y funciona bien. Aquí está mi guión

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

Supongamos que el contenido del feed está en el archivo sample_rss.xml. Ese contenido se introduce en xml ed -d, que elimina cualquier nota que coincida con la expresión XPath dada. La expresión XPath busca cualquiera <item> que no tenga un nodo <title>que contenga el texto "Project Foo".

Esto parece funcionar bien y también estoy muy contento con el tiempo de ejecución:

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

Cuidado con los espacios de nombres

Si desea que esto funcione con feeds rss o atom adecuados, puede observar que feedcontiene un atributo de espacio de nombres XML ( xmlns), como en este ejemplo de 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>

Entonces, ¡el script anterior ya no funcionará! Me causó bastante dolor de cabeza solucionarlo, pero aquí se explica cómo hacerlo funcionar:

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

Más sobre este problema de espacio de nombres aquí:http://xmlstar.sourceforge.net/doc/UG/ch05.html

información relacionada