2011-10-26 4 views
18

두 개의 xml 요소의 동등성에 관심이 있습니다. 그리고 요소의 tostring을 테스트하는 것이 효과가 있다는 것을 알았습니다. 그러나 그것은 해커처럼 보인다. 두 개의 etree 요소의 동등성을 테스트하는 더 좋은 방법이 있습니까? 예 :테스트 동등성 xml.etree.ElementTree

import xml.etree.ElementTree as etree 
h1 = etree.Element('hat',{'color':'red'}) 
h2 = etree.Element('hat',{'color':'red'}) 

h1 == h2 

거짓

etree.tostring(h1) == etree.tostring(h2) 

진정한

+0

두 요소를 비교하는 기능에서 찾을 수있다 [이타 마르의 대답 (http://stackoverflow.com/a/24349916/2371522) 아래 . – One

답변

0

금되지 플레이트를 수행합니다. 당신이 가진 것은 좋은 비교입니다. XML의 마지막 부분은 TEXT입니다.

+0

예. 서식을 지정하는 데 신경 쓰면 ET로 변환 한 다음 문자열로 덤프하고 비교하십시오. – Wyrmwood

2

복잡한 구조를 비교하는 일반적인 방법은 일반적인 고유 한 텍스트 표현으로 덤프하고 결과 문자열이 동일한 지 비교하는 것입니다.

수신 된 두 개의 json 문자열을 비교하려면 json 개체로 변환 한 다음 동일한 변환기로 문자열로 변환하고 비교합니다. 나는 json 피드를 확인하기 위해 그것을했다, 그것은 잘 작동한다.

XML의 경우 거의 동일하지만 ".text"부분 (태그 외부에있는 텍스트 또는 공백이 아닌)을 처리 (strip? remove?)해야 할 수도 있습니다.

간단히 말해서, 귀하의 컨텍스트에 따라 동일한 2 개의 XML이 동일한 문자열 표현을 갖게되는 한 솔루션은 해킹이 아닙니다.

3

실제로 얼마나 많은 어린이가 있을지 모르고 모든 어린이를 검색에 포함하려는 경우 두 노드를 비교하는 것이 실제로 가장 좋은 방법인지 확인하십시오. 물론

, 당신은 단순히 당신이 입증되는 것과 같은 자식 노드가있는 경우, 당신은 단순히 태그, ATTRIB을 비교할 수 있고, 꼬리 속성 :

if h1.tag == h2.tag and h1.attrib == h2.attrib and h1.tail == h2.tail: 
    print("h1 and h2 are the same") 
else 
    print("h1 and h2 are the different") 

내가의 주요 혜택을 볼 수 없습니다 그러나 tostring을 사용합니다.

+0

필요에 따라 텍스트를 던져 넣을 수도 있습니다 :'h1.text == h2.text' – bmaupin

+0

이것은 어린이 요소를 비교하지 않습니다 ... – drevicko

7

문자열 비교가 항상 작동하는 것은 아닙니다. 속성의 순서는 두 노드를 동등하게 고려할 때 중요하지 않습니다. 그러나 문자열 비교를 수행하는 경우 순서가 분명 중요합니다.

>>> from lxml import etree 
>>> h1 = etree.XML('<hat color="blue" price="39.90"/>') 
>>> h2 = etree.XML('<hat price="39.90" color="blue"/>') 
>>> etree.tostring(h1) == etree.tostring(h2) 
False 

이를 :

나는 그것이 문제 나 기능이 있지만,이 파일이나 문자열에서 구문 분석하는 경우 lxml.etree의 나의 버전은 속성의 순서를 유지 있는지 확실하지 않습니다 버전 의존적 일 수도 있습니다 (저는 Ubuntu에서 lxml.etree 2.3.2와 함께 Python 2.7.3을 사용합니다). 1 년 전쯤에 속성의 순서를 제어 할 수있는 방법을 찾지 못했다는 것을 기억합니다. 가독성을 위해.

다른 serializer에서 생성 된 XML 파일을 비교해야하므로 모든 노드의 태그, 텍스트, 특성 및 하위를 재귀 적으로 비교하는 것 외에 다른 방법은 없습니다. 물론 흥미로운 점이 있다면 물론 꼬리도 있습니다. LXML 및 xml.etree.ElementTree

진리

비교는 구현 의존 할 수 있다는 것이다. 분명히 lxml은 주문 된 dict 또는 이와 유사한 것을 사용합니다. 표준 xml.etree입니다.ElementTree는 속성의 순서가 유지되지 않습니다. (예, 개행 문자가 누락하지만 사소한 문제입니다.)

Python 2.7.1 (r271:86832, Nov 27 2010, 17:19:03) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> from lxml import etree >>> h1 = etree.XML('<hat color="blue" price="39.90"/>') >>> h2 = etree.XML('<hat price="39.90" color="blue"/>') >>> etree.tostring(h1) == etree.tostring(h2) False >>> etree.tostring(h1) '<hat color="blue" price="39.90"/>' >>> etree.tostring(h2) '<hat price="39.90" color="blue"/>' >>> etree.dump(h1) <hat color="blue" price="39.90"/>>>> etree.dump(h2) <hat price="39.90" color="blue"/>>>> 

>>> import xml.etree.ElementTree as ET 
>>> h1 = ET.XML('<hat color="blue" price="39.90"/>') 
>>> h1 
<Element 'hat' at 0x2858978> 
>>> h2 = ET.XML('<hat price="39.90" color="blue"/>') 
>>> ET.dump(h1) 
<hat color="blue" price="39.90" /> 
>>> ET.dump(h2) 
<hat color="blue" price="39.90" /> 
>>> ET.tostring(h1) == ET.tostring(h2) 
True 
>>> ET.dump(h1) == ET.dump(h2) 
<hat color="blue" price="39.90" /> 
<hat color="blue" price="39.90" /> 
True 

또 다른 질문이 비교 중요하지 않은 whan을 간주되는 수 있습니다. 예를 들어, 일부 조각은 여분의 공백을 포함 할 수 있으므로 신경 쓰지 않아도됩니다. 이런 방식으로, 우리가 필요로하는 정확하게 작동하는 직렬화 함수를 작성하는 것이 항상 더 좋습니다.

+1

'.dump (...)'는'None'을 반환하므로' ET.dump (h1) == ET.dump (h2)'는 실제로'None'과'None'을 비교합니다. –

4

속성이 순서에 의존하지 않으며 (다른 이유로) XML에 대해 직렬화 및 비 직렬화가 작동하지 않습니다. 이 두 요소는 논리적으로 동일하지만 다른 문자열입니다.

<THING a="foo" b="bar"></THING> 
<THING b="bar" a="foo" /> 

정확하게 요소를 비교하는 방법은 까다 롭습니다. 제가 말할 수있는 한, 요소 트리에 내장 된 것은 없습니다. 이 작업을 직접 수행하고 아래 코드를 사용했습니다. 내 필요에 따라 작동하지만 큰 XML 구조에는 적합하지 않으며 빠르고 효율적이지 않습니다! 이것은 equality 함수가 아닌 ordering 함수이므로 0의 결과는 동일하고 다른 것은 그렇지 않습니다. True 또는 False를 반환하는 함수로 래핑하는 것은 독자의 연습 과제로 남겨 둡니다!

def cmp_el(a,b): 
    if a.tag < b.tag: 
     return -1 
    elif a.tag > b.tag: 
     return 1 
    elif a.tail < b.tail: 
     return -1 
    elif a.tail > b.tail: 
     return 1 

    #compare attributes 
    aitems = a.attrib.items() 
    aitems.sort() 
    bitems = b.attrib.items() 
    bitems.sort() 
    if aitems < bitems: 
     return -1 
    elif aitems > bitems: 
     return 1 

    #compare child nodes 
    achildren = list(a) 
    achildren.sort(cmp=cmp_el) 
    bchildren = list(b) 
    bchildren.sort(cmp=cmp_el) 

    for achild, bchild in zip(achildren, bchildren): 
     cmpval = cmp_el(achild, bchild) 
     if cmpval < 0: 
      return -1 
     elif cmpval > 0: 
      return 1  

    #must be equal 
    return 0 
+0

두 XML 파일을 비교할 때의 주된 원인은 위에서 말한 것과 같은 형식입니다. 그리고 대부분의 경우 발음 영역은 꼬리 부분의 공백이나 개행 문자에 있습니다. 논리적으로 똑같은 두 개의 테스트 용 XML 파일이 있었고 코드는 동일하다는 것을 알지 못했습니다. 그러나 코드에서 .tail 비교를 제거하고 매력처럼 작동했습니다. – PMN

18

이 비교 기능은 나를 위해 작동 :

def elements_equal(e1, e2): 
    if e1.tag != e2.tag: return False 
    if e1.text != e2.text: return False 
    if e1.tail != e2.tail: return False 
    if e1.attrib != e2.attrib: return False 
    if len(e1) != len(e2): return False 
    return all(elements_equal(c1, c2) for c1, c2 in zip(e1, e2)) 
+3

이것은 해결책입니다. 공백이 방해하지 않는지 확인하십시오 (예 : 'etree.XMLParser (remove_blank_text = True)'를 사용하여. 'all()'에리스트를 작성하는 것을 피함으로써 개선하십시오. 'zip()'은 이전에'len()'이 테스트 되었기 때문에 작동합니다. – One

+1

깔끔한! 이것은 동일한 태그 넷을 가진 요소조차도 요소 순서에 관계없이 작동하는 것처럼 보입니다. – Fredrik