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 latitle
etiqueta 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 python
y 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.xml
archivo 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, sed
es bastante poderoso y debería ser posible hacer esto con un solo sed
comando.
Mirando hacia adelante a sus respuestas :-)
Respuesta1
Como se sugiere en los comentarios, intenté usar xmlstarlet
para 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 feed
contiene 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