2010-08-04 4 views
1

XML 문서의 모든 것을 2 개의 태그 사이에서 제거하려합니다. 파이썬 & lxml을 사용합니다. 문제는 태그가 트리의 다른 분기에있을 수 있지만 (예 : 항상 동일한 깊이에 있음) 예제 문서가 이와 같이 보일 수 있다는 것입니다.xml 트리 분기에 걸쳐있는 두 태그 사이의 모든 것을 제거하십시오

<root> 
    <p> Hello world <start />this is a paragraph </p> 
    <p> Goodbye world. <end />I'm leaving now </p> 
</root> 

저는 시작 태그와 종료 태그 사이의 모든 것을 제거하고 싶습니다. 하나의 p 태그에있는을 초래 :

<root> 
    <p> Hello world I'm leaving now </p> 
</root> 

사람이이 LXML & 파이썬을 사용하여 수행 할 수있는 방법을 어떤 생각을 가지고 있습니까?

답변

0

당신은이 SAX와 같은 target parser interface 사용하여 시도 할 수 :

from lxml import etree 

class SkipStartEndTarget: 
    def __init__(self, *args, **kwargs): 
     self.builder = etree.TreeBuilder() 
     self.skip = False 

    def start(self, tag, attrib, nsmap=None): 
     if tag == 'start': 
      self.skip = True 
     if not self.skip: 
      self.builder.start(tag, attrib, nsmap) 

    def data(self, data): 
     if not self.skip: 
      self.builder.data(data) 

    def comment(self, comment): 
     if not self.skip: 
      self.builder.comment(self) 

    def pi(self, target, data): 
     if not self.skip: 
      self.builder.pi(target, data) 

    def end(self, tag): 
     if not self.skip: 
      self.builder.end(tag) 
     if tag == 'end': 
      self.skip = False 

    def close(self): 
     self.skip = False 
     return self.builder.close() 

당신은 다음 parser target을 만들기 위해 SkipStartEndTarget 클래스를 사용할 수 있으며, 다음과 같이 그 대상과의 사용자 정의 XMLParser을 만듭니다

parser = etree.XMLParser(target=SkipStartEndTarget()) 

필요한 경우 파서에 다른 파서 옵션을 제공 할 수 있습니다. 그럼 당신은 예를 들어, 사용중인 파서 기능이 파서를 제공 할 수

elem = etree.fromstring(xml_str, parser=parser) 

을 아마 인 (이것은 또한 etree.XML()etree.parse()와 함께 작동, 당신은 심지어 etree.setdefaultparser()와 기본 파서로 파서를 설정할 수 있습니다 좋은 아이디어). 당신을 여행 할 수있는 한가지 : 심지어 etree.parse()으로, 이것은 elementtree를 반환하지 않을 것이지만, 언제나 한 요소 (etree.XML()etree.fromstring()처럼)를 반환 할 것입니다. 나는 이것이 (아직) 완료 될 수 있다고 생각하지 않는다. 그래서 이것이 당신에게 문제가된다면, 어떻게 든 해결해야 할 것이다.

sax 이벤트의 elementtree를 lxml.sax과 함께 생성하는 것도 가능합니다. 다소 어려울 수도 있고 느릴 수도 있습니다. 위의 예와는 달리 elementtree를 반환하지만 etree.parse()을 정상적으로 사용할 때 얻을 수있는 .docinfo을 제공하지 않는다고 생각합니다. 나는 또한 (현재) 코멘트와 파이를 지원하지 않는다고 믿는다.(아직 사용하지 않았기 때문에 지금은 더 이상 정확하지 않습니다.)

도큐먼트를 파싱하는 SAX와 같은 접근법은 <start/><end/> 사이의 모든 것을 건너 뛰어도 우물 귀하의 예에서는 그렇지만 두 번째 <p><p2> 인 경우에는 그렇지 않습니다. 결국 <p>....</p2>으로 끝날 것입니다.

1

당신은 손에 혼란스러워하고 XML 중첩 규칙을 고의적으로 왜곡 한 사람을 때려야합니다.

태그를 인식하고 <end/>에 도달 할 때까지 입력을 삭제하려면 가장 좋은 방법은 SAX입니다. SAX는 lxml보다 장점이 있습니다. 왜냐하면 lxml은 당신이 그것들을 만지기 전에 이미 이혼 한 상태에서 시작과 끝을 이미 가지고있는 동안 어휘마다 임의의 행동을 취할 수 있기 때문입니다.

그 동안 문서를 사용 가능한 XML로 변환 할 수 있습니다.

+0

오, 나는 그것에 대해 뭔가를 할 수 있었으면 좋겠다. 이것은 ODT 파일이다. 그들은 "변경 사항 추적"을 위해이 파일을 사용합니다. 불행히도 etree를 사용하는 파일에서 다른 조작을 많이하고 있으므로 SAX로 전환 할 수 있는지 잘 모르겠습니다. 그것들을 조사 할 필요가 있습니다. – user61000

1

나는이 돌 저를 원하는 것 일부 사람들이 알고 있지만, 당신은 정규식을 사용할 수 있습니다 : 그것은 유효한 XML되지 때 당신은 XML 파서를 사용할 수 없습니다

import re 
new_string = re.sub(r'<start />(.*?)<end />', '', your_string, re.S) 

.

+0

나는 동의하는 경향이 있습니다. 어떤 상황에서는이 방법이 덜 효과적 일 수 있지만, 성능상의 문제가 많이 발생하지는 않습니다. –

+2

XML은 완벽하게 유효합니다. 완전한 자기 닫는 태그. 정규식 경로에 대해 생각했지만 문서가 거대하고 제거해야 할이 많은 경우가 있습니다. – user61000

+0

@ user61 맞습니다, 그것은 * 유효한 * XML입니다. 더 나은 단어를 알아 두세요. "적절한"XML이 아닌 것 같습니다. 어쨌든, 슬 루프 모드로 읽을 수 있다면 크기에 관계없이 괜찮을 것입니다. – NullUserException

관련 문제