특정 요소가 포함된 XML 노드 삭제

특정 요소가 포함된 XML 노드 삭제

요소가 포함된 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>

관련 정보