可以告诉ElementTree保留属性的顺序吗?

发布于 2021-01-29 19:35:57

我使用ElementTree在python中编写了一个相当简单的过滤器,以调整某些xml文件的上下文。它或多或少地起作用。

但是它重新排序了各种标签的属性,我希望它不要这样做。

有谁知道我可以抛出的开关使其保持在指定的顺序?

上下文

我正在使用一个粒子物理工具,该工具具有基于xml文件的复杂但奇怪的配置系统。以这种方式设置的许多事物中包括各种静态数据文件的路径。这些路径被硬编码到现有的xml中,没有基于环境变量设置或更改它们的功能,在我们的本地安装中,它们必须位于不同的位置。

这不是灾难,因为我们使用的源代码控制和构建控制工具相结合,使我们可以使用本地副本对某些文件进行阴影处理。但是,即使以为数据字段是静态的,xml也不是静态的,所以我写了一个脚本来修复路径,但是由于属性重排,本地版本和主版本之间的差异很难理解,因此不必要。


这是我第一次带ElementTree旋转(而且只有我的第五个或第六个python项目),所以也许我只是做错了。

为简化起见,代码摘要如下:

tree = elementtree.ElementTree.parse(inputfile)
i = tree.getiterator()
for e in i:
    e.text = filter(e.text)
tree.write(outputfile)
关注者
0
被浏览
43
1 个回答
  • 面试哥
    面试哥 2021-01-30
    为面试而生,有面试问题,就找面试哥。

    在@bobince的答案和这两个帮助下(设置属性顺序,覆盖模块方法)

    我设法修复了这只猴子的脏污,建议使用另一个模块更好地处理这种情况,但是在这种情况下是不可能的:

    # =======================================================================
    # Monkey patch ElementTree
    import xml.etree.ElementTree as ET
    
    def _serialize_xml(write, elem, encoding, qnames, namespaces):
        tag = elem.tag
        text = elem.text
        if tag is ET.Comment:
            write("<!--%s-->" % ET._encode(text, encoding))
        elif tag is ET.ProcessingInstruction:
            write("<?%s?>" % ET._encode(text, encoding))
        else:
            tag = qnames[tag]
            if tag is None:
                if text:
                    write(ET._escape_cdata(text, encoding))
                for e in elem:
                    _serialize_xml(write, e, encoding, qnames, None)
            else:
                write("<" + tag)
                items = elem.items()
                if items or namespaces:
                    if namespaces:
                        for v, k in sorted(namespaces.items(),
                                           key=lambda x: x[1]):  # sort on prefix
                            if k:
                                k = ":" + k
                            write(" xmlns%s=\"%s\"" % (
                                k.encode(encoding),
                                ET._escape_attrib(v, encoding)
                                ))
                    #for k, v in sorted(items):  # lexical order
                    for k, v in items: # Monkey patch
                        if isinstance(k, ET.QName):
                            k = k.text
                        if isinstance(v, ET.QName):
                            v = qnames[v.text]
                        else:
                            v = ET._escape_attrib(v, encoding)
                        write(" %s=\"%s\"" % (qnames[k], v))
                if text or len(elem):
                    write(">")
                    if text:
                        write(ET._escape_cdata(text, encoding))
                    for e in elem:
                        _serialize_xml(write, e, encoding, qnames, None)
                    write("</" + tag + ">")
                else:
                    write(" />")
        if elem.tail:
            write(ET._escape_cdata(elem.tail, encoding))
    
    ET._serialize_xml = _serialize_xml
    
    from collections import OrderedDict
    
    class OrderedXMLTreeBuilder(ET.XMLTreeBuilder):
        def _start_list(self, tag, attrib_in):
            fixname = self._fixname
            tag = fixname(tag)
            attrib = OrderedDict()
            if attrib_in:
                for i in range(0, len(attrib_in), 2):
                    attrib[fixname(attrib_in[i])] = self._fixtext(attrib_in[i+1])
            return self._target.start(tag, attrib)
    
    # =======================================================================
    

    然后在您的代码中:

    tree = ET.parse(pathToFile, OrderedXMLTreeBuilder())
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看