【问题标题】:How to prevent XMLSerializer.serializeToString() from re-ordering attributes?如何防止 XMLSerializer.serializeToString() 重新排序属性?
【发布时间】:2010-08-23 21:39:20
【问题描述】:

我正在使用 jQuery 将任意 XML 字符串(较大文档的片段)加载到浏览器 DOM 中并对其进行操作,然后使用 XMLSerializer 将它们加载回字符串并将它们发送回服务器,在那里进行处理(通过 python 和 lxml) 并重新集成到一个完整的 XML 文档中。

XML 在 git 存储库中开始和结束。我发现 XMLSerializer 处理的元素的属性顺序颠倒了,导致我的存储库中出现虚假更改,如下所示:

- <literal><token kind="w" id="en-us-esv-xeaugcbzgo">sent</token><token kind="s" id="en-us-esv-xeaugcbzgw"> </token></literal>
+ <literal><token id="en-us-esv-xeaugcbzgo" kind="w">sent</token><token id="en-us-esv-xeaugcbzgw" kind="s"> </token></literal>

这不是我使用的任何工具的错误。当然,xml 元素上的属性顺序并不重要但是, 因为 git 是一个面向行的 SCM,这些虚假和微不足道的变化会分散我想要跟踪的实际实质性变化。

问题:有没有办法防止序列化程序重新排序我的属性?或者,是否存在任何工具来指定/限制属性的顺序?

为清楚起见在上面进行了编辑:我知道,根据 XML 规范,“开始标记或空元素标记中的属性规范的顺序并不重要”:http://www.w3.org/TR/REC-xml/#sec-starttags .可以这么说,属性的顺序对我来说很重要 :)

【问题讨论】:

  • 看起来,属性最终是按字母顺序排列的。您不能将其设置为约定吗?或许对操纵 XML 的 Python 代码的一个小改动会使它们立即以“正确”的顺序出现?
  • 这可能是我最终要做的。很不方便的是,我的 XML 操作工具(lxml,libxml2 的 python 包装器)没有将属性排序视为重要的(并且正确地如此!)。因此,我对上述问题进行了编辑。

标签: javascript xml xml-serialization lxml


【解决方案1】:

如果这很重要,那么错误不在于重新排序属性,而在于它很重要。让它随心所欲地订购它们,然后修复错误。

编辑:

等一下。为什么将其放入存储库?如果它是输出而不是源,那么它在存储库中的值是作为非编辑资源而不是源,并且它的存储是为了方便。否则,你为什么要让计算机进程改变它?

这类似于将二进制文件放入存储库中,原因与为什么这通常很糟糕,以及产生异常的原因相同。

【讨论】:

  • SCM 通常是面向行的,不幸的是,AFAIK 没有任何 SCM 系统能够“理解”XML 到能够忽略 XML 中无关紧要的东西的程度。就此而言,定义两个 XML 文件是否“相同”取决于数据的语义。
  • @Jim,那么 XML 不是要使用的输出。
  • 这不是一个错误,只是一个方便的问题:属性的重新排序会掩盖正在应用于数据的其他有意义的更改。 XML 是否是正确的输出,或者它是否属于存储库,不在问题的范围内。
【解决方案2】:

我已经按照@Tomalak 建议的方向,正在“修复”服务器端的订单。值得庆幸的是,原始顺序是按字母顺序排列的,而 XMLSerializer 生成的顺序是反字母顺序排列的。我的服务器端 XML 工具 lxml 维护文档属性顺序,因此颠倒顺序很简单:

xmls = json.loads(self.data['xmls'])
out = []
for xml in xmls:
    # DOM adds an XHTML namespace... silly DOM.
    xml = xml.replace('xmlns="http://www.w3.org/1999/xhtml"', '')
    tree = ET.fromstring(xml)
    for el in tree.xpath('//*'):
        attrs = dict(el.attrib)
        keys = el.attrib.keys()  # el.attrib preserves attribute order
        keys.reverse()  # But the browser DOM has reversed that order.
        # Put them back in the order we want.
        el.attrib.clear()
        for k in keys:
            el.attrib[k] = attrs[k]
    out.append(ET.tostring(tree, encoding=unicode))

我的基于行的差异再次有用!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-27
    • 1970-01-01
    • 2013-07-08
    • 2019-06-19
    • 2020-12-02
    • 2013-03-21
    • 2012-01-11
    • 2016-01-25
    相关资源
    最近更新 更多