比较XML片段?

2024-04-25 17:53:29 发布

您现在位置:Python中文网/ 问答频道 /正文

another SO question的基础上,如何检查两个格式良好的XML片段在语义上是否相等。我所需要的只是“相等”与否,因为我将此用于单元测试。

在我想要的系统中,这些是相等的(注意“start”的顺序 和“结束”):

<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<Stats start="1275955200" end="1276041599">
</Stats>

# Reordered start and end

<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<Stats end="1276041599" start="1275955200" >
</Stats>

我可以使用lmxl和其他工具,一个只允许重新排序属性的简单函数也可以工作得很好!


基于IanB答案的工作片段:

from formencode.doctest_xml_compare import xml_compare
# have to strip these or fromstring carps
xml1 = """    <?xml version='1.0' encoding='utf-8' standalone='yes'?>
    <Stats start="1275955200" end="1276041599"></Stats>"""
xml2 = """     <?xml version='1.0' encoding='utf-8' standalone='yes'?>
    <Stats end="1276041599" start="1275955200"></Stats>"""
xml3 = """ <?xml version='1.0' encoding='utf-8' standalone='yes'?>
    <Stats start="1275955200"></Stats>"""

from lxml import etree
tree1 = etree.fromstring(xml1.strip())
tree2 = etree.fromstring(xml2.strip())
tree3 = etree.fromstring(xml3.strip())

import sys
reporter = lambda x: sys.stdout.write(x + "\n")

assert xml_compare(tree1,tree2,reporter)
assert xml_compare(tree1,tree3,reporter) is False

Tags: importversionstatsxmlstartutfencodingyes
3条回答

元素的顺序在XML中是很重要的,这可能是为什么大多数其他方法建议如果顺序不同的话会比较不相等。。。即使元素具有相同的属性和文本内容。

但我也想要一个顺序不敏感的比较,所以我想到了这个:

from lxml import etree
import xmltodict  # pip install xmltodict


def normalise_dict(d):
    """
    Recursively convert dict-like object (eg OrderedDict) into plain dict.
    Sorts list values.
    """
    out = {}
    for k, v in dict(d).iteritems():
        if hasattr(v, 'iteritems'):
            out[k] = normalise_dict(v)
        elif isinstance(v, list):
            out[k] = []
            for item in sorted(v):
                if hasattr(item, 'iteritems'):
                    out[k].append(normalise_dict(item))
                else:
                    out[k].append(item)
        else:
            out[k] = v
    return out


def xml_compare(a, b):
    """
    Compares two XML documents (as string or etree)

    Does not care about element order
    """
    if not isinstance(a, basestring):
        a = etree.tostring(a)
    if not isinstance(b, basestring):
        b = etree.tostring(b)
    a = normalise_dict(xmltodict.parse(a))
    b = normalise_dict(xmltodict.parse(b))
    return a == b

我遇到了同样的问题:我想比较两个属性相同但顺序不同的文档。

lxml中的XML规范化(C14N)似乎对此很有效,但我绝对不是XML专家。我很想知道是否有人能指出这种方法的缺点。

parser = etree.XMLParser(remove_blank_text=True)

xml1 = etree.fromstring(xml_string1, parser)
xml2 = etree.fromstring(xml_string2, parser)

print "xml1 == xml2: " + str(xml1 == xml2)

ppxml1 = etree.tostring(xml1, pretty_print=True)
ppxml2 = etree.tostring(xml2, pretty_print=True)

print "pretty(xml1) == pretty(xml2): " + str(ppxml1 == ppxml2)

xml_string_io1 = StringIO()
xml1.getroottree().write_c14n(xml_string_io1)
cxml1 = xml_string_io1.getvalue()

xml_string_io2 = StringIO()
xml2.getroottree().write_c14n(xml_string_io2)
cxml2 = xml_string_io2.getvalue()

print "canonicalize(xml1) == canonicalize(xml2): " + str(cxml1 == cxml2)

运行此命令可以:

$ python test.py 
xml1 == xml2: false
pretty(xml1) == pretty(xml2): false
canonicalize(xml1) == canonicalize(xml2): true

您可以使用formencode.doctest_xml_compare——xml_compare函数比较两个ElementTree或lxml树。

相关问题 更多 >

    热门问题