12

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

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

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

4

9 回答 9

11

为了保持属性顺序,我做了这个微小的修改:

from collections import OrderedDict

在元素类中:

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

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

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

请注意,开始标签或空元素标签中属性规范的顺序并不重要。

于 2011-12-01T17:00:35.210 回答
9

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

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

于 2009-03-19T15:42:55.117 回答
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("\"")

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

于 2011-05-06T08:36:58.840 回答
3

在 Python 2.7 之前,我使用了以下热补丁

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. 热补丁是邪恶的。
于 2011-12-08T09:47:45.260 回答
3

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

对于 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 个属性是可选的呢?

关键是重新排序是一个比递增排序所带来的问题更大的问题。它与程序员的思维方式或功能应该如何工作相混淆。至少排序应该是可配置的/可选的。

原谅我糟糕的英语。它不是我的主要语言。

于 2014-03-10T15:02:13.600 回答
1

1.自定义你自己的'Element.writexml'方法。

从 'minidom.py' 将 Element 的 writexml 代码复制到您自己的文件中。

将其重命名为 writexml_nosort,

删除 'a_names.sort()' (python 2.7) 或将 'a_names = sorted(attrs.keys())' 更改为 'a_names = attrs.keys()' (python 3.4)

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

minidom.Element.writexml = writexml_nosort;

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

right_order = ['a', 'b', 'c', 'a1', 'b1']

3.调整你元素的 _attrs

node._attrs = OrderedDict( [(k,node._attrs[k]) for k in right_order ])

于 2015-04-17T10:37:44.680 回答
0

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

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

您可以将其更改为

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

对于空闲,我不得不将文件更改为 /usr/lib/python3.6/xml/dom. 似乎 Idle 不遵循sys.path顺序。不要忘记先备份。

于 2020-04-16T13:02:01.827 回答
0

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

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

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

于 2020-04-17T08:51:58.963 回答
-1

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

于 2009-06-13T00:11:41.523 回答