我正在使用Python(2.7/3.8(,并处理一些复杂的XML,这些XML可以一起进行比较。XML的顺序可能不同,我正在构建一个函数,作为排序规则(查看节点属性,然后查看节点子级(。
我已经研究了一些不同的相关问题,但它们都不适用于我的场景:
- Python通过和递归地标记和属性对XML元素进行排序
- 使用python按标记对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>
编辑
正如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
,然后您可以使用regex从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,test123123(,并将其作为元组拆分到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))