【问题标题】:Python XML Sorting by Attribute/ChildrenPython XML 按属性/子项排序
【发布时间】:2020-09-26 06:15:59
【问题描述】:

我正在使用 Python (2.7/3.8) 并处理一些比较复杂的 XML。 XML 的顺序可以不同,我正在构建一个函数作为排序规则(查看节点属性,然后查看子节点)。

我查看了几个不同的相关问题,但都不适用于我的场景:

我可以使用key=lambda child: child.tag 进行排序,但是我通常希望使用属性而不是标签名称。

在最基本的情况下,我希望能够按属性名称排序,检查 ['id', 'label', 'value'] 中的任何一个是否作为属性存在,并将其用作键。无论如何,我似乎无法弄清楚为什么 child.tag 可以进行排序,但 child.get('id') 不能。

import xml.etree.ElementTree as etree
    
input = '''
    <root>
        <node id="7"></node>
        <node id="10"></node>
        <node id="5"></node>
    </root>
'''

root = etree.fromstring(input)

root[:] = sorted(root, key=lambda child: child.get('id'))

xmlstr = etree.tostring(root, encoding="utf-8", method="xml")
print(xmlstr.decode("utf-8"))

返回:

<root>
    <node id="7" />
    <node id="5" />
    <node id="10" />
</root>

预期:

<root>
    <node id="5" />
    <node id="7" />
    <node id="10" />
</root>

编辑

正如所提到的,用 int() 包装 child.get('id') 确实可以解决问题,但是代码必须另外适用于同时包含字母 + 数字的输入,例如 id="node1", " node15”等

例如:

<root>
    <node id="node10" />
    <node id="node7" />
    <node id="node5" />
</root>

预期:

<root>
    <node id="node5" />
    <node id="node7" />
    <node id="node10" />
</root>

【问题讨论】:

  • 您能否发布带有值id="node1", "node15" 和预期输出的示例
  • @deadshot - 已发布。感谢帮助。看来我需要研究自然排序,所以我将开始。
  • @user2288151:请将问题和答案分开。如果您有替代或更详细的解决方案,请将其作为新答案发布。
  • @mzjn,分开。谢谢

标签: python xml sorting elementtree


【解决方案1】:

您应该将id 值转换为int 并且您可以使用正则表达式从id 中提取didgit

import re


root[:] = sorted(root, key=lambda child: int(re.search('\d+', child.get('id')).group()))

xmlstr = etree.tostring(root, encoding="utf-8", method="xml")
print(xmlstr.decode("utf-8"))

输出:

<root>
    <node id="node5" />
    <node id="node7" />
    <node id="node10" />
</root>

【讨论】:

  • 谢谢!解决了这个谜......现在,我将如何让这两个整数/字符串工作,例如如果 id 是
  • 我已经更新了主要问题的答案,该答案适用于格式为 test、test123、123 等的字符串。
【解决方案2】:

为了进一步构建 deadshot 的方法,我使用下面的 split_key 函数,我将任意时间的字符串 (test, test123, 123) 拆分为字符串/int 部分作为元组,以允许通过 sorted 方法轻松排序。

def split_key(key):
    regex = re.compile(r'^(?P<letters>.*?)(?P<numbers>\d*)$')
    letters = regex.search(key).group('letters') or ''
    numbers = regex.search(key).group('numbers') or 0
    return (letters, int(numbers))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多