2011-12-05 56 views
6

我有一个遗留的文件格式,我将其转换为XML进行处理。该结构可以概括为:LXML - 排序标记顺序

<A> 
    <A01>X</A01> 
    <A02>Y</A02> 
    <A03>Z</A03> 
</A> 

标签的数字部分可以去从01到99,并可能有差距。作为处理的一部分,某些记录可能会添加额外的标签。处理完成后,我通过漫游树将文件转换回传统格式。这些文件相当大(约150,000个节点)。

这样做的一个问题是,一些使用传统格式的软件假设标签(或者说它的转换时间字段)将按字母数字顺序排列,但默认情况下,新标签将被添加到该分支然后导致它们以错误顺序从迭代器中出来。

我可以使用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> 
+2

我不太确定XML架构非常深思熟虑过。 A01和A02不是同一类型的东西吗?他们应该共享相同的元素名称。这个数字应该是一个属性,而不是标签名称的一部分。此外,标签名称当然应该比这更可读,但我意识到它们可能只是一个例子。 –

+0

不幸的是,我无法控制传统格式,而是直接翻译了它如何将数据存储在键/值对中。在原始文件中,它可能会说“A01 = Bob”,然后应用程序知道该号码保存着名字。 – George

+0

有很多方法可以在XML中实现它,但是您在这里展示的不是一个非常有意义的翻译。您的模式将变得复杂且不断变化。我会建议''其中item是A01,A02表示的东西。 –

回答

17

可以写一个辅助函数以便在正确的位置插入一个新的元素,但是如果不知道更多关于结构的信息,就很难使其具有通用性。

这里是在整个文件分类的子元素的简单的例子:

from lxml import etree 

data = """<X> 
    <X03>3</X03> 
    <X02>2</X02> 
    <A> 
     <A02>Y</A02> 
     <A01>X</A01> 
     <A03>Z</A03> 
    </A> 
    <X01>1</X01> 
    <B> 
     <B01>Z</B01> 
     <B02>X</B02> 
     <B03>C</B03> 
    </B> 
</X>""" 

doc = etree.XML(data,etree.XMLParser(remove_blank_text=True)) 

for parent in doc.xpath('//*[./*]'): # Search for parent elements 
    parent[:] = sorted(parent,key=lambda x: x.tag) 

print etree.tostring(doc,pretty_print=True) 

产量:

<X> 
    <A> 
    <A01>X</A01> 
    <A02>Y</A02> 
    <A03>Z</A03> 
    </A> 
    <B> 
    <B01>Z</B01> 
    <B02>X</B02> 
    <B03>C</B03> 
    </B> 
    <X01>1</X01> 
    <X02>2</X02> 
    <X03>3</X03> 
</X> 
+0

谢谢 - lamba函数只是我需要的。 – George

+0

谢谢...我发现这些文章也很有用:http://wiki.python.org/moin/HowTo/Sorting http://www.secnetix.de/olli/Python/lambda_functions.hawk – Homer6

+0

我不明白你为什么使用'parent [:] =分配。 – Sdwdaw

4

你可以这样你的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)