使用minidom进行修改时保留属性的顺序

时间:2009-03-19 15:23:11

标签: python xml minidom

使用minidom处理XML时,有没有办法可以保留属性的原始顺序?

说我有:<color red="255" green="255" blue="233" /> 当我用minidom修改它时,属性按字母顺序重新排列为蓝色,绿色和红色。我想保留原来的订单。

我通过循环遍历elements = doc.getElementsByTagName('color')返回的元素来处理文件,然后我执行这样的分配e.attributes["red"].value = "233"

9 个答案:

答案 0 :(得分:9)

为了保持属性顺序,我在minidom中做了一点修改:

from collections import OrderedDict

在Element类中:

__init__(...)
    self._attrs = OrderedDict()
    #self._attrs = {}
writexml(...)
    #a_names.sort()

现在这只适用于Python 2.7+ 我不确定它是否真的有效=&gt;使用风险自负......

请注意,您不应该依赖属性顺序:

请注意,start-tag或empty-element标记中的属性规范顺序并不重要。

答案 1 :(得分:8)

  

使用minidom处理XML时,有没有办法可以保留属性的原始顺序?

使用minidom no时,用于存储属性的数据类型是无序字典。 pxdom可以做到这一点,但速度要慢得多。

答案 2 :(得分:3)

很明显,xml属性没有排序。 我刚刚发现了这种奇怪的行为!

这似乎与xml.dom.minidom.Element.writexml函数中添加的排序有关!!

class Element(Node):
... snip ...

    def writexml(self, writer, indent="", addindent="", newl=""):
        # indent = current indentation
        # addindent = indentation to add to higher levels
        # newl = newline string
        writer.write(indent+"<" + self.tagName)

        attrs = self._get_attributes()
        a_names = attrs.keys()
        a_names.sort()
--------^^^^^^^^^^^^^^
        for a_name in a_names:
            writer.write(" %s=\"" % a_name)
            _write_data(writer, attrs[a_name].value)
            writer.write("\"")

删除该行可恢复保持原始文档顺序的行为。 当您必须使用diff工具检查代码中没有错误时,这是​​一个好主意。

答案 3 :(得分:3)

在Python 2.7之前,我使用了以下 hotpatching

class _MinidomHooker(object):
    def __enter__(self):
        minidom.NamedNodeMap.keys_orig = minidom.NamedNodeMap.keys
        minidom.NamedNodeMap.keys = self._NamedNodeMap_keys_hook
        return self

    def __exit__(self, *args):
        minidom.NamedNodeMap.keys = minidom.NamedNodeMap.keys_orig
        del minidom.NamedNodeMap.keys_orig

    @staticmethod
    def _NamedNodeMap_keys_hook(node_map):
        class OrderPreservingList(list):
            def sort(self):
                pass
        return OrderPreservingList(node_map.keys_orig())

以这种方式使用:

with _MinidomHooker():
    document.writexml(...)

声明:

  1. 你不应该依赖属性的顺序。
  2. 改变NamedNodeMap类不是线程安全的。
  3. hotpatching 是邪恶的。

答案 4 :(得分:2)

你们可以提出你想要的免责声明。 虽然重新排序属性对程序没有意义,但它确实对程序员/用户有意义。

对于Fredrick来说,重要的是要有RGB顺序,因为这就是颜色的顺序。 对我来说,它特别是name属性。

比较

<field name="url" type="string" indexed="true" stored="true" required="true" multiValued="false"/> <!-- ID -->
<field name="forkortelse" type="string" indexed="true" stored="true" required="false" multiValued="false" />
<field name="kortform" type="text_general" indexed="true" stored="true" required="false" multiValued="false" />
<field name="dato" type="date" indexed="true" stored="true" required="false" multiValued="false" />
<field name="nummer" type="int" indexed="true" stored="true" required="false" multiValued="false" />
<field name="kilde" type="string" indexed="true" stored="true" required="false" multiValued="false" />
<field name="tittel" type="text_general" indexed="true" stored="true" multiValued="true"/>

<field indexed="true" multiValued="false" name="forkortelse" required="false" stored="true" type="string"/>
<field indexed="true" multiValued="false" name="kortform" required="false" stored="true" type="text_general"/>
<field indexed="true" multiValued="false" name="dato" required="false" stored="true" type="date"/>
<field indexed="true" multiValued="false" name="nummer" required="false" stored="true" type="int"/>
<field indexed="true" multiValued="false" name="kilde" required="false" stored="true" type="string"/>
<field an_optional_attr="OMG!" an_optional_attr2="OMG!!" indexed="true" name="tittel" stored="true" type="text_general"/>

虽然阅读并非不可能,但并不容易。名称是重要的属性。隐藏名称字段的方式并不好。如果名称是左边的15个属性,前面的7个属性是可选的,该怎么办?

重点是重新排序是一个比acsending排序反过来更大的问题。它与程序员的思维方式或功能如何运作相混淆。至少顺序应该是可配置/可选的。

请原谅我可怜的英语。这不是我的主要语言。

答案 5 :(得分:1)

1.定制您自己的&#39; Element.writexml&#39;方法

来自&#39; minidom.py&#39;将Element的writexml代码复制到您自己的文件中。

将其重命名为writexml_nosort,

删除&#39; a_names.sort()&#39; (python 2.7)  或更改&#39; a_names =已排序(attrs.keys())&#39;到&#39; a_names = attrs.keys()&#39;(python 3.4)

将Element的方法更改为您自己的方法:

minidom.Element.writexml = writexml_nosort;

2.自定义您喜欢的订单:

right_order = [&#39; a&#39;,&#39; b&#39;,&#39; c&#39;,&#39; a1&#39;,&#39; b1&#39; ]

3.调整您的元素_atters

node._attrs = OrderedDict(right_order中k的[(k,node._attrs [k])])

答案 6 :(得分:0)

在Element类中使用writexlm函数编写时,属性按最小顺序排列。 这样完成:

a-name = sorted(attrs.keys())

您可以将其更改为

a-name = list(attrs.keys())

对于空闲状态,我不得不在 /usr/lib/python3.6/xml/dom。空闲似乎没有遵循sys.path的顺序。 别忘了先备份。

答案 7 :(得分:0)

在处理XML时,有没有一种方法可以保留属性的原始顺序 渺小?

是的。从Python 3.8开始,序列化XML文档时将保留原始属性顺序。

请参见https://docs.python.org/3/library/xml.dom.minidom.html#xml.dom.minidom.Node.writexml

答案 8 :(得分:-1)

我最终使用lxml库而不是minidom。