
Quiero eliminar todas las marcas de posición de un archivo KML que contenga el elemento <tessellate>
. El siguiente bloque debe sertotalmenteremoto:
<Placemark>
<styleUrl>#m_ylw-pushpin330</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
0.0000000000000,0.0000000000000,0 0.0000000000000,0.0000000000000,0
</coordinates>
</LineString>
</Placemark>
Probé algunas expresiones regulares de Perl no codiciosas sin suerte (se eliminan muchas cosas junto con la primera <Placemark>
):
sed -r ':a; N; $!ba; s/\n\t*//g' myplaces.kml |
perl -pe 's|<Placemark>.*?<tessellate>.*?</Placemark>||g'
Creo que un analizador XML es el camino a seguir, pero leí la documentación de xmlstarlet y no llegué a ninguna parte. Por lo tanto, cualquier solución en xmlstarlet, python, etc. también es bienvenida.
Respuesta1
Con xmlstarlet
:
xmlstarlet ed -d '//Placemark[.//tessellate]' < myplaces.kml
Y como kml
utiliza espacios de nombres, primero debe definirlos (consulte la documentación xmlstarlet)
xmlstarlet ed -N 'ns=http://www.opengis.net/kml/2.2' -d '//ns:Placemark[.//ns:tessellate]'
Con perl
, necesitarías procesar el archivo como un todo (no línea por línea) y agregar la s
bandera a s///
. E incluso entonces, incluso con una coincidencia no codiciosa, aún coincidiría desde el primero <Placemark>
hasta el siguiente </Placemark>
que ocurre después del siguiente <tessellate>
. Entonces necesitarías escribirlo algo como:
perl -0777 -pe 's|(<Placemark>.*?</Placemark>)|
$1 =~ /<tessellate>/?"":$1|gse'
Respuesta2
Dado este archivo de prueba:
start
<Placemark>
<tessellate>1</tessellate>
</Placemark>
middle1
<Placemark>
</Placemark>
middle2
<Placemark>
<tessellate>1</tessellate>
</Placemark>
end
Si hace perl -0 -pe 's|<Placemark>.*?<tessellate>.*?</Placemark>||gs'
lo que sugirió, eliminará demasiado:
start
middle1
end
Esto se debe a que la expresión regular solo mira hacia adelante. Encuentra una etiqueta inicial, toma todo hasta la primera etiqueta teselada y hasta la siguiente etiqueta final. Desafortunadamente, no le importa si consume más etiquetas de inicio en el camino...
Si quieres hacerlo con expresiones regulares, debes procesar cada bloque por sí solo:
perl -0 -pe 's|<Placemark>.*?</Placemark>|$&=~/<tessellate>/?"":$&|gse'
Esto debería dar el resultado deseado.
Respuesta3
Usando Python (2.7) con módulos estándar:
archivo test.xml
:
<Container>
<Placemark>
<KeepMe/>
</Placemark>
<Placemark>
<styleUrl>#m_ylw-pushpin330</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
0.0000000000000,0.0000000000000,0 0.0000000000000,0.0000000000000,0
</coordinates>
</LineString>
</Placemark>
</Container>
Y el programa:
#! /usr/bin/env python
from __future__ import print_function # works on 2.x and 3.x
from lxml import etree
file_name = 'test.xml'
root = etree.parse(file_name)
for element in root.iterfind('.//Placemark'):
if(element.find('.//tessellate')) is not None:
element.getparent().remove(element)
print(etree.tostring(root))
da como salida:
<Container>
<Placemark>
<KeepMe/>
</Placemark>
</Container>