在Python中进行单元测试中的XML比较

Ada*_*ott 33 python xml elementtree

我有一个可以从XML字符串构建自己的对象,并将自己写入XML字符串.我想编写一个单元测试来测试通过XML的循环跳过,但是我在比较两个XML版本时遇到了麻烦.空白和属性顺序似乎是问题.有关如何做到这一点的任何建议?这是在Python中,我正在使用ElementTree(这并不重要,因为我只是在这个级别处理字符串中的XML).

Mik*_*bov 16

这是一个老问题,但接受的Kozyarchuk的答案对我来说不起作用,因为属性顺序,并且minidom解决方案也不起作用(不知道为什么,我没有调试它).

这就是我最终提出的:

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)
Run Code Online (Sandbox Code Playgroud)

这也产生了一个diff,在大型xml文件的情况下可能会有所帮助.

  • 由于字符串编码问题,无论我使用“bytes()”、“bytearray()”或“encode('utf-8')”的哪种组合,我都无法在Python3中使用它。我不确定这是否是图书馆的问题,或者我是否只是错过了一些东西,但这对我不起作用。 (2认同)

Koz*_*huk 14

首先规范化2 XML,然后你可以比较它们.我使用了以下使用lxml

obj1 = objectify.fromstring(expect)
expect = etree.tostring(obj1)
obj2 = objectify.fromstring(xml)
result = etree.tostring(obj2)
self.assertEquals(expect, result)
Run Code Online (Sandbox Code Playgroud)

  • 嘿.稍微注意一点,etree没有记录任何特定顺序序列化属性的保证.至少目前ElementTree的纯Python实现确实对它们进行了sort(),但是不清楚你是否可以依赖它. (7认同)
  • 注意:序列化可能因Python的版本而异,尤其是属性顺序. (3认同)

bob*_*nce 7

如果问题实际上只是空格和属性顺序,并且您没有其他构造而不是文本和元素需要担心,则可以使用标准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
Run Code Online (Sandbox Code Playgroud)

如果您需要更全面的等效比较,涵盖其他类型节点的可能性,包括CDATA,PI,实体引用,注释,文档类型,命名空间等,您可以使用DOM Level 3 Core方法isEqualNode.minidom和etree都没有,但是pxdom是一个支持它的实现:

def isEqualXML(a, b):
    da, db= pxdom.parseString(a), pxdom.parseString(a)
    return da.isEqualNode(db)
Run Code Online (Sandbox Code Playgroud)

(如果需要指定实体引用和CDATA部分是否与其替换的等效项匹配,则可能需要更改解析中的某些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
Run Code Online (Sandbox Code Playgroud)


and*_*wrk 5

使用xmldiff,这是一个python工具,可以找出两个相似XML文件之间的差异,就像diff那样.