문제

XML 문자열에서 자체적으로 빌드 할 수있는 객체가 있고 XML 문자열에 자체적으로 기록됩니다. XML을 통해 라운드 트립을 테스트하기 위해 단위 테스트를 작성하고 싶지만 두 XML 버전을 비교하는 데 어려움이 있습니다. 공백 및 속성 순서가 문제인 것 같습니다. 이 작업을 수행하는 방법에 대한 제안이 있습니까? 이것은 파이썬에 있으며 ElementTree를 사용하고 있습니다 (이 수준에서 문자열에서 XML을 다루기 때문에 여기서는 중요하지 않습니다).

도움이 되었습니까?

해결책

먼저 2 XML을 정규화 한 다음 비교할 수 있습니다. LXML을 사용하여 다음을 사용했습니다

obj1 = objectify.fromstring(expect)
expect = etree.tostring(obj1)
obj2 = objectify.fromstring(xml)
result = etree.tostring(obj2)
self.assertEquals(expect, result)

다른 팁

이것은 오래된 질문이지만 받아 들여졌습니다 Kozyarchuk의 대답 속성 순서 때문에 나에게 효과가 없습니다. 미니 돔 솔루션 그대로 작동하지 않습니다.

이것이 내가 마침내 생각한 것입니다.

from doctest import Example
from lxml.doctestcompare import LXMLOutputChecker

class XmlTest(TestCase):
    def assertXmlEqual(self, got, want):
        checker = LXMLOutputChecker()
        if not checker.check_output(want, got, 0):
            message = checker.output_difference(Example("", want), got, 0)
            raise AssertionError(message)

이것은 또한 큰 XML 파일의 경우 도움이 될 수있는 차이를 생성합니다.

문제가 실제로 공백 및 속성 순서 일뿐이고 걱정할 텍스트와 요소 이상의 다른 구성이 없다면 표준 XML 파서를 사용하여 문자열을 구문 분석하고 노드를 수동으로 비교할 수 있습니다. Minidom을 사용하는 예는 다음과 같습니다. 그러나 Etree에서 동일한 글을 간단히 쓸 수 있습니다.

def isEqualXML(a, b):
    da, db= minidom.parseString(a), minidom.parseString(b)
    return isEqualElement(da.documentElement, db.documentElement)

def isEqualElement(a, b):
    if a.tagName!=b.tagName:
        return False
    if sorted(a.attributes.items())!=sorted(b.attributes.items()):
        return False
    if len(a.childNodes)!=len(b.childNodes):
        return False
    for ac, bc in zip(a.childNodes, b.childNodes):
        if ac.nodeType!=bc.nodeType:
            return False
        if ac.nodeType==ac.TEXT_NODE and ac.data!=bc.data:
            return False
        if ac.nodeType==ac.ELEMENT_NODE and not isEqualElement(ac, bc):
            return False
    return True

CDATA, PIS, 엔티티 참조, 댓글, 문서, 네임 스페이스 등을 포함한 다른 유형의 노드의 가능성을 다루는보다 철저한 동등성 비교가 필요한 경우 DOM 레벨 3 코어 메소드 ISEQUALNODE를 사용할 수 있습니다. Minidom이나 Etree는이를 가지고 있지 않지만 PXDOM은이를 지원하는 하나의 구현입니다.

def isEqualXML(a, b):
    da, db= pxdom.parseString(a), pxdom.parseString(a)
    return da.isEqualNode(db)

(엔티티 참조 및 CDA Section이 대체 된 동등한 요소와 일치하는지 여부를 지정 해야하는 경우 구문 분석에서 일부 DOMConfiguration 옵션을 변경할 수 있습니다.)

약간 더 로터리를 수행하는 방법은 구문 분석 한 다음 표준 형태로 다시 시리얼링하고 문자열 비교를 수행하는 것입니다. 다시 PXDOM은 DOM Level 3 LS 옵션 'Canonical-Form'을 지원합니다. STDLIB의 MinIDOM 구현을 사용하는 대안적인 방법은 C14N을 사용하는 것입니다. 그러나 pyxml 확장자가이를 위해 설치해야하므로 stdlib 내에서 여전히 할 수 없습니다.

from xml.dom.ext import c14n

def isEqualXML(a, b):
    da, bd= minidom.parseString(a), minidom.parseString(b)
    a, b= c14n.Canonicalize(da), c14n.Canonicalize(db)
    return a==b

사용 xmldiff, 두 개의 유사한 XML 파일의 차이점을 파악하는 Python 도구.

XML 데이터를 전혀 검토하는 이유는 무엇입니까?

객체 직렬화를 테스트하는 방법은 객체의 인스턴스를 생성하고 직렬화하고, 새 객체로 삼키고, 두 객체를 비교하는 것입니다. 직렬화 또는 사막화를 중단하는 변경을 수행하면이 테스트가 실패합니다.

XML 데이터를 확인하는 유일한 것은 Serializer가 Deserializer가 요구하는 것에 대한 슈퍼 세트를 방출하는 경우, Deserializer는 예상치 못한 것들을 조용히 무시하는 것입니다.

물론, 다른 것이 직렬화 된 데이터를 소비한다면, 그것은 또 다른 문제입니다. 그러나이 경우 XML에 대한 스키마를 설정하고 검증하는 것에 대해 생각해야합니다.

나는 또한이 문제가 있었고 오늘 그것을 파고 들었습니다. 그만큼 doctestcompare 접근하다 충분하지만, 나는 찾았습니다 Ian Bicking 그것은 기반입니다 formencode.doctest_xml_compare. 지금은 나타납니다 여기. 보시다시피, 그것은 매우 간단한 기능입니다. doctestcompare (내가 추측하지만 doctestcompare 모든 실패와 더 정교한 점검을 수집하고 있습니다). 어쨌든 복사/가져 오기 xml_compare 밖으로 formencode 좋은 해결책 일 수 있습니다.

Java 구성 요소 dbUnit 많은 XML 비교를 수행하므로 접근 방식을 살펴 보는 것이 유용 할 수 있습니다 (특히 이미 다루었을 수있는 gotchas를 찾는 데).

def xml_to_json(self, xml):
    """Receive 1 lxml etree object and return a json string"""
    def recursive_dict(element):
        return (element.tag.split('}')[1],
                dict(map(recursive_dict, element.getchildren()),
                     **element.attrib))
    return json.dumps(dict([recursive_dict(xml)]),
                      default=lambda x: str(x))

def assertEqualXML(self, xml_real, xml_expected):
    """Receive 2 objectify objects and show a diff assert if exists."""
    xml_expected_str = json.loads(self.xml_to_json(xml_expected))
    xml_real_str = json.loads(self.xml_to_json(xml_real))
    self.maxDiff = None
    self.assertEqual(xml_real_str, xml_expected_str)

다음과 같은 출력을 볼 수 있습니다.

                u'date': u'2016-11-22T19:55:02',
                u'item2': u'MX-INV0007',
         -      u'item3': u'Payments',
         ?                  ^^^
         +      u'item3': u'OAYments',
         ?                  ^^^ +

쉽게 수행 할 수 있습니다 minidom:

class XmlTest(TestCase):
    def assertXmlEqual(self, got, want):
        return self.assertEqual(parseString(got).toxml(), parseString(want).toxml())
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top