Python LXML-分类标签顺序
我有一个遗留文件格式,我正在将其转换为XML进行处理。结构可概括为:Python LXML-分类标签顺序,python,xml,lxml,Python,Xml,Lxml,我有一个遗留文件格式,我正在将其转换为XML进行处理。结构可概括为: <A> <A01>X</A01> <A02>Y</A02> <A03>Z</A03> </A> X Y Z 标签的数字部分可以从01到99,并且可能存在间隙。作为处理的一部分,某些记录可能会添加额外的标记。处理完成后,我将通过遍历树将文件转换回传统格式。这些文件相当大(约150000个节点) 这样做的一
<A>
<A01>X</A01>
<A02>Y</A02>
<A03>Z</A03>
</A>
X
Y
Z
标签的数字部分可以从01到99,并且可能存在间隙。作为处理的一部分,某些记录可能会添加额外的标记。处理完成后,我将通过遍历树将文件转换回传统格式。这些文件相当大(约150000个节点)
这样做的一个问题是,一些使用传统格式的软件假设标记(或者更确切地说,转换时的字段)将以字母数字顺序排列,但默认情况下,新标记将添加到分支的末尾,从而导致它们以错误的顺序从迭代器中出来
每次添加新标记时,我都可以使用xpath根据标记名查找前面的同级,但我的问题是,是否有更简单的方法在导出之前立即对树进行排序
编辑:
我想我已经过度概括了结构
记录可以包含如上所述的多个级别,以提供如下内容:
<X>
<X01>1</X01>
<X02>2</X02>
<X03>3</X03>
<A>
<A01>X</A01>
<A02>Y</A02>
<A03>Z</A03>
</A>
<B>
<B01>Z</B02>
<B02>X</B02>
<B03>C</B03>
</B>
</X>
1.
2.
3.
X
Y
Z
Z
X
C
您可以对xml元素进行如下排序:
from operator import attrgetter
from lxml import etree
root = etree.parse(xmlfile)
children = list(root)
sorted_list = sorted(children, key=attrgetter('tag'))
如果运行速度太慢,您可能只需对标记名进行排序,然后使用xpath获取节点:
tag_list = [item.tag for item in root]
sorted_taglist = sorted(tag_list)
可以编写一个helper函数来在正确的位置插入新元素,但是如果不了解更多关于结构的信息,就很难使其通用 下面是一个在整个文档中对子元素进行排序的简短示例:
从lxml导入etree
data=”“”
3.
2.
Y
X
Z
1.
Z
X
C
"""
doc=etree.XML(数据,etree.XMLParser(remove\u blank\u text=True))
对于doc.xpath('/*[./*]')中的父元素:#搜索父元素
父项[:]=已排序(父项,键=lambda x:x.tag)
打印etree.tostring(doc,pretty\u print=True)
屈服:
X
Y
Z
Z
X
C
1.
2.
3.
在谷歌上搜索XML分类器,我到了这里。基于@MattH的工作,我制作了一个更完整和可调节的功能:
#!python3
from lxml import etree
import sys
if len(sys.argv) < 3:
print("usage : xml_sorted.py file_in.xml file_out.xml")
exit(0)
filename_in=sys.argv[1]
filename_out=sys.argv[2]
def getSortValue(elem):
if isinstance(elem,etree._Comment):
# sort comment by its content
return elem.text
else:
# sort entities by tag and then by name
return elem.tag + elem.attrib.get('name','')
doc=etree.parse(filename_in)
for parent in doc.xpath('//*[./*]'): # Search for parent elements
parent[:] = sorted(parent,key=lambda x: getSortValue(x))
with open(filename_out,"wb") as file:
file.write(etree.tostring(doc,pretty_print=True))
#!蟒蛇3
从lxml导入etree
导入系统
如果len(sys.argv)<3:
打印(“用法:xml\u sorted.py file\u in.xml file\u out.xml”)
出口(0)
filename_in=sys.argv[1]
filename_out=sys.argv[2]
def getSortValue(元素):
如果不存在(元素、etree.\u注释):
#按内容对评论进行排序
返回元素文本
其他:
#按标记排序实体,然后按名称排序
返回elem.tag+elem.attrib.get('name','')
doc=etree.parse(文件名\u in)
对于doc.xpath('/*[./*]')中的父元素:#搜索父元素
父项[:]=已排序(父项,键=lambda x:getSortValue(x))
打开(文件名为“wb”)作为文件:
file.write(etree.tostring(doc,pretty\u print=True))
我不太确定XML模式是否经过深思熟虑。A01和A02不是同一类型的东西吗?它们应该共享相同的元素名称。数字可能应该是一个属性,而不是标记名的一部分。当然,标记名的可读性应该更高,但我意识到它们可能只是一个示例。不幸的是,我无法控制传统格式,这是它如何以键/值对存储数据的直接转换。在原始文件中,它可能会说“A01=Bob”,然后应用程序就会知道这个数字是以这个名字命名的。在XML中有很多方法可以实现这一点,但您在这里展示的方法并不是非常语义化的翻译。您的模式将是复杂且不断变化的。我建议value
其中item是A01、A02所代表的东西。当我说键/值对时,我指的是一个静态的键列表,已知这些键表示某种东西-因此它说的Bob
实际上是Bob
,但只不过是遗留应用程序(~20年前)是用这些不透明的数字字段名编写的。谢谢-lamba函数正是我所需要的。谢谢。。。我发现这些文章也很有用:我不明白为什么在赋值中使用parent[:]=
。@Sdwdaw因为我想修改现有序列的内容,比如对象parent
。不创建该名称的新列表。如果您得到TypeError:'