
Quero remover todos os marcadores de um arquivo KML que contém o elemento <tessellate>
. O seguinte bloco deve sercompletamenteremovido:
<Placemark>
<styleUrl>#m_ylw-pushpin330</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
0.0000000000000,0.0000000000000,0 0.0000000000000,0.0000000000000,0
</coordinates>
</LineString>
</Placemark>
Eu tentei alguns regex perl não gananciosos sem sorte (muitas coisas são removidas junto com o primeiro <Placemark>
):
sed -r ':a; N; $!ba; s/\n\t*//g' myplaces.kml |
perl -pe 's|<Placemark>.*?<tessellate>.*?</Placemark>||g'
Acredito que um analisador XML é o caminho a seguir, mas li a documentação do xmlstarlet e não cheguei a lugar nenhum. Portanto, quaisquer soluções em xmlstarlet, python, etc. também são bem-vindas!
Responder1
Com xmlstarlet
:
xmlstarlet ed -d '//Placemark[.//tessellate]' < myplaces.kml
E como kml
usa namespaces, você deve defini-lo primeiro (veja a documentação do xmlstarlet)
xmlstarlet ed -N 'ns=http://www.opengis.net/kml/2.2' -d '//ns:Placemark[.//ns:tessellate]'
Com perl
, você precisaria processar o arquivo como um todo (não linha por linha) e adicionar o s
sinalizador a s///
. E mesmo assim, mesmo com uma correspondência não gananciosa, ainda corresponderia do primeiro <Placemark>
ao próximo </Placemark>
que ocorresse após o próximo <tessellate>
. Então você precisaria escrever algo como:
perl -0777 -pe 's|(<Placemark>.*?</Placemark>)|
$1 =~ /<tessellate>/?"":$1|gse'
Responder2
Dado este arquivo de teste:
start
<Placemark>
<tessellate>1</tessellate>
</Placemark>
middle1
<Placemark>
</Placemark>
middle2
<Placemark>
<tessellate>1</tessellate>
</Placemark>
end
Se você fizer perl -0 -pe 's|<Placemark>.*?<tessellate>.*?</Placemark>||gs'
como sugeriu, removerá muito:
start
middle1
end
Isso ocorre porque a regex está apenas olhando para frente. Ele encontra uma tag inicial, leva tudo até a primeira tag tessellate e até a próxima tag final. Infelizmente ele não se importa se consome mais tags iniciais no caminho...
Se você quiser fazer isso com regexes você terá que processar cada bloco por conta própria:
perl -0 -pe 's|<Placemark>.*?</Placemark>|$&=~/<tessellate>/?"":$&|gse'
Isso deve dar o resultado desejado.
Responder3
Usando Python (2.7) com módulos padrão:
arquivo 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>
E o 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))
dá como saída:
<Container>
<Placemark>
<KeepMe/>
</Placemark>
</Container>