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