Python XML 按 Attribute/Children 排序

Python XML Sorting by Attribute/Children

我正在使用 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"))

哪个returns:

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

预计:

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

编辑

正如 deadshot 提到的那样,用 int() 包装 child.get('id') 确实解决了这个问题,但是代码必须另外适用于同时具有字母 + 数字的输入,例如 id ="节点1"、"节点15"等

例如:

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

预计:

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

您应该将 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>

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

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))