
我想從包含該元素的 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>