比较python中的两个xml文件

san*_*kar 8 python xml parsing

我是python编程的新手,'我有一些麻烦理解这个概念.我想比较两个xml文件.这些xml文件非常大.我将举例说明我想要比较的文件类型.

xmlfile1:

<xml>
    <property1>
          <property2>    
               <property3>

               </property3>
          </property2>    
    </property1>    
</xml>
Run Code Online (Sandbox Code Playgroud)

xml file2:

<xml>
    <property1>
        <property2>    
            <property3> 
                <property4>

                </property4>    
            </property3>
        </property2>    
    </property1>

</xml>
Run Code Online (Sandbox Code Playgroud)

我命名的property1,property2与文件中实际的不同.xml文件中有很多属性.我希望比较两个xml文件.

我正在使用lxml解析器来尝试比较这两个文件并打印出它们之间的区别.

我不知道如何解析它并自动进行比较.

我尝试通过lxml解析器阅读,但我无法理解如何将它用于我的问题.

有人可以告诉我如何处理这个问题.

代码片段非常有用

还有一个问题,我是否遵循了正确的概念,或者我错过了其他的东西?请纠正我所说的任何新概念

Nic*_*tin 8

这实际上是一个相当具有挑战性的问题(由于"差异"意味着通常在这里的旁观者眼中,因为将存在您可能不希望标记为差异的语义"等效"信息).

您可以尝试使用xmldiff,它基于" 层次结构化信息中的更改检测 "一文中的工作.

  • 死灵回馈:GPL意味着,如果用户要求,则必须向用户提供源代码。这并不意味着您*具有*公开给所有人(也不免费),并且您可以始终通过附加合同对用户施加其他限制。 (2认同)

Ste*_*ite 6

如果您的目的是比较 XML 内容和属性,而不仅仅是逐字节比较文件,那么问题就很微妙,因此没有适合所有情况的解决方案。

您必须了解 XML 文件中重要的内容。

元素标签中列出的属性的顺序通常不重要。也就是说,两个仅元素属性顺序不同的 XML 文件通常应该被判断为相同。

但这是通用部分。

棘手的部分取决于应用程序。例如,文件的某些元素的空格格式可能并不重要,并且可能会向 XML 添加空格以提高可读性。等等。

该模块的最新版本ElementTree有一个函数canonicalize(),可以通过将 XML 字符串转换为规范格式来处理更简单的情况。

我在最近项目的单元测试中使用了此函数,将已知的 XML 输出与有时会更改属性顺序的包的输出进行比较。在这种情况下,文本元素中的空格并不重要,但有时会用于格式化。

import xml.etree.ElementTree as ET
def _canonicalize_XML( xml_str ):
    """ Canonicalizes XML strings, so they are safe to 
        compare directly. 
        Strips white space from text content."""

    if not hasattr( ET, "canonicalize" ):
        raise Exception( "ElementTree missing canonicalize()" )

    root = ET.fromstring( xml_str )
    rootstr = ET.tostring( root )
    return ET.canonicalize( rootstr, strip_text=True )
Run Code Online (Sandbox Code Playgroud)

要使用它,像这样:

file1 = ET.parse('file1.xml')
file2 = ET.parse('file2.xml')

canon1 = _canonicalize_XML( ET.tostring( file1.getroot() ) )
canon2 = _canonicalize_XML( ET.tostring( file2.getroot() ) )

print( canon1 == canon2 )
Run Code Online (Sandbox Code Playgroud)

在我的发行版中,Python 2 没有canonicalize(),但 Python 3 有。


小智 5

我解决这个问题的方法是将每个 XML 转换为xml.etree.ElementTree并遍历每个层。我还包括在进行比较时忽略属性列表的功能。

第一个代码块包含使用的类:

import xml.etree.ElementTree as ET
import logging

class XmlTree():

    def __init__(self):
        self.hdlr = logging.FileHandler('xml-comparison.log')
        self.formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

    @staticmethod
    def convert_string_to_tree( xmlString):

        return ET.fromstring(xmlString)

    def xml_compare(self, x1, x2, excludes=[]):
        """
        Compares two xml etrees
        :param x1: the first tree
        :param x2: the second tree
        :param excludes: list of string of attributes to exclude from comparison
        :return:
            True if both files match
        """

        if x1.tag != x2.tag:
            self.logger.debug('Tags do not match: %s and %s' % (x1.tag, x2.tag))
            return False
        for name, value in x1.attrib.items():
            if not name in excludes:
                if x2.attrib.get(name) != value:
                    self.logger.debug('Attributes do not match: %s=%r, %s=%r'
                                 % (name, value, name, x2.attrib.get(name)))
                    return False
        for name in x2.attrib.keys():
            if not name in excludes:
                if name not in x1.attrib:
                    self.logger.debug('x2 has an attribute x1 is missing: %s'
                                 % name)
                    return False
        if not self.text_compare(x1.text, x2.text):
            self.logger.debug('text: %r != %r' % (x1.text, x2.text))
            return False
        if not self.text_compare(x1.tail, x2.tail):
            self.logger.debug('tail: %r != %r' % (x1.tail, x2.tail))
            return False
        cl1 = x1.getchildren()
        cl2 = x2.getchildren()
        if len(cl1) != len(cl2):
            self.logger.debug('children length differs, %i != %i'
                         % (len(cl1), len(cl2)))
            return False
        i = 0
        for c1, c2 in zip(cl1, cl2):
            i += 1
            if not c1.tag in excludes:
                if not self.xml_compare(c1, c2, excludes):
                    self.logger.debug('children %i do not match: %s'
                                 % (i, c1.tag))
                    return False
        return True

    def text_compare(self, t1, t2):
        """
        Compare two text strings
        :param t1: text one
        :param t2: text two
        :return:
            True if a match
        """
        if not t1 and not t2:
            return True
        if t1 == '*' or t2 == '*':
            return True
        return (t1 or '').strip() == (t2 or '').strip()
Run Code Online (Sandbox Code Playgroud)

第二个代码块包含几个 XML 示例及其比较:

xml1 = "<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>"

xml2 = "<note><to>Tove</to><from>Daniel</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>"

tree1 = XmlTree.convert_string_to_tree(xml1)
tree2 = XmlTree.convert_string_to_tree(xml2)

comparator = XmlTree()

if comparator.xml_compare(tree1, tree2, ["from"]):
    print "XMLs match"
else:
    print "XMLs don't match"
Run Code Online (Sandbox Code Playgroud)

此代码的大部分功劳必须归功于 syawar