Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python LXML-分类标签顺序_Python_Xml_Lxml - Fatal编程技术网

Python LXML-分类标签顺序

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个节点) 这样做的一

我有一个遗留文件格式,我正在将其转换为XML进行处理。结构可概括为:

<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:'