我想从包含该元素的 KML 文件中删除所有地标<tessellate>
。以下块应该是完全地删除:
<Placemark>
<styleUrl>#m_ylw-pushpin330</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
0.0000000000000,0.0000000000000,0 0.0000000000000,0.0000000000000,0
</coordinates>
</LineString>
</Placemark>
我尝试了一些非贪婪的 Perl 正则表达式,但没有成功(很多东西与第一个一起被删除<Placemark>
):
sed -r ':a; N; $!ba; s/\n\t*//g' myplaces.kml |
perl -pe 's|<Placemark>.*?<tessellate>.*?</Placemark>||g'
我相信 XML 解析器是可行的方法,但我阅读了 xmlstarlet 的文档却一无所获。所以也欢迎任何 xmlstarlet、python 等解决方案!
答案1
和xmlstarlet
:
xmlstarlet ed -d '//Placemark[.//tessellate]' < myplaces.kml
当kml
使用命名空间时,您必须首先定义它(请参阅 xmlstarlet 文档)
xmlstarlet ed -N 'ns=http://www.opengis.net/kml/2.2' -d '//ns:Placemark[.//ns:tessellate]'
使用perl
,您需要将文件作为一个整体(而不是逐行)处理并将标志添加s
到s///
.即使这样,即使使用非贪婪匹配,它仍然会从第一个匹配到下一个之后发生的下<Placemark>
一个。所以你需要这样写:</Placemark>
<tessellate>
perl -0777 -pe 's|(<Placemark>.*?</Placemark>)|
$1 =~ /<tessellate>/?"":$1|gse'
答案2
给定这个测试文件:
start
<Placemark>
<tessellate>1</tessellate>
</Placemark>
middle1
<Placemark>
</Placemark>
middle2
<Placemark>
<tessellate>1</tessellate>
</Placemark>
end
如果你确实perl -0 -pe 's|<Placemark>.*?<tessellate>.*?</Placemark>||gs'
像你建议的那样,它会删除太多:
start
middle1
end
这是因为正则表达式只是向前看。它找到一个开始标签,获取第一个细分标签和下一个结束标签之间的所有内容。不幸的是,它并不关心它是否会消耗更多的开始标签......
如果您想使用正则表达式来执行此操作,则必须单独处理每个块:
perl -0 -pe 's|<Placemark>.*?</Placemark>|$&=~/<tessellate>/?"":$&|gse'
这应该会给出所需的结果。
答案3
将 Python (2.7) 与标准模块结合使用:
文件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>
和程序:
#! /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))
给出输出:
<Container>
<Placemark>
<KeepMe/>
</Placemark>
</Container>