【问题标题】:python lxml write to file in predefined orderpython lxml以预定义的顺序写入文件
【发布时间】:2014-07-30 14:16:52
【问题描述】:

我想写以下 lxml etree 子元素

<ElementProtocolat0x3803048>,
<ElementStudyEventDefat0x3803108>,
<ElementFormDefat0x3803248>,
<ElementItemGroupDefat0x38032c8>,
<ElementClinicalDataat0x3803408>,
<ElementItemGroupDataat0x38035c8>,
<ElementFormDefat0x38036c8>,

预定义的顺序写入我的 odm xml 文件。即

<ElementProtocolat0x3803048>,
<ElementStudyEventDefat0x3803108>,
<ElementFormDefat0x3803248>,
<ElementFormDefat0x38036c8>,
<ElementItemGroupDefat0x38032c8>,
<ElementItemGroupDataat0x38035c8>,
<ElementClinicalDataat0x3803408>,
....

有没有办法对元素进行排序,即使用预定义的列表?

predefined_order = ['Protocol', 'StudyEventDef','FormDef','ItemGroupDef','ItemDef','CodeList']

【问题讨论】:

  • ClinicalData在哪里?
  • 哦,对不起,我忘了它在最后一个位置..predefined_order = ['Protocol', 'StudyEventDef','FormDef','ItemGroupDef','ItemDef','CodeList', '临床数据']
  • 是列表中的子元素字符串吗?
  • 不,它们在 ElementTree 对象中:etree.SubElement(root, 'FormDef')
  • 您是在问如何重新排序 lxml 树,还是在问如何根据预定义的列表进行排序?如果是前者,见stackoverflow.com/questions/8385358/lxml-sorting-tag-order

标签: python sorting lxml elementtree


【解决方案1】:

此示例演示:

  • 如何读入 XML 文件,
  • 元素是一个列表,可以这样操作
  • 如何根据可匹配子字符串的预定义顺序对列表进行排序
  • 如何写出 XML 文件
from lxml import etree
import re

# Parse the XML and find the root
with open('input.xml') as input_file:
    tree = etree.parse(input_file)
root = tree.getroot()

# Find the list to sort and sort it
some_arbitrary_expression_to_find_the_list = '.'
element_list = tree.xpath(some_arbitrary_expression_to_find_the_list)[0]

predefined_order = [
    'Protocol',
    'StudyEventDef',
    'FormDef',
    'ItemGroupDef',
    'ItemGroupData',
    'ItemDef',
    'CodeList',
    'ClinicalData']
filter = re.compile(r'Element(.*)at0x.*')

element_list[:] = sorted(
    element_list[:],
    key = lambda x: predefined_order.index(filter.match(x.tag).group(1)))

# Write the XML to the output file
with open('output.xml', 'w') as output_file:
    output_file.write(etree.tostring(tree, pretty_print = True))

示例输入:

<stuff>
<ElementProtocolat0x3803048 />
<ElementStudyEventDefat0x3803108 />
<ElementFormDefat0x3803248 />
<ElementItemGroupDefat0x38032c8>Random Text</ElementItemGroupDefat0x38032c8>
<ElementClinicalDataat0x3803408 />
<ElementItemGroupDataat0x38035c8><tag1><tag2 attr="random tags"/></tag1></ElementItemGroupDataat0x38035c8>
<ElementFormDefat0x38036c8 />
</stuff>

输出:

<stuff>
<ElementProtocolat0x3803048/>
<ElementStudyEventDefat0x3803108/>
<ElementFormDefat0x3803248/>
<ElementFormDefat0x38036c8/>
<ElementItemGroupDefat0x38032c8>Random Text</ElementItemGroupDefat0x38032c8>
<ElementItemGroupDataat0x38035c8><tag1><tag2 attr="random tags"/></tag1></ElementItemGroupDataat0x38035c8>
<ElementClinicalDataat0x3803408/>
</stuff>

【讨论】:

  • 非常感谢!最后我用 for 循环解决了这个问题,但这是更好的解决方案!
【解决方案2】:

抱歉,我缺乏对 xml 的了解,但我尝试仅使用我对 Python 的基本知识按排序顺序格式化您的数据。

import re
data = """<ElementProtocolat0x3803048>,
<ElementStudyEventDefat0x3803108>,
<ElementFormDefat0x3803248>,
<ElementItemGroupDefat0x38032c8>,
<ElementClinicalDataat0x3803408>,
<ElementItemGroupDataat0x38035c8>,
<ElementFormDefat0x38036c8>,"""

predefined_order = ['Protocol','StudyEventDef','FormDef','ItemGroupDef','ItemGroupData','CodeList', 'ClinicalData']

fh1 = open("something.xml","w")
for i in predefined_order:
    for j in data.split(','):
        if re.search(i,j):
            fh1.write(j + ',')

输出:

<ElementProtocolat0x3803048>,
<ElementStudyEventDefat0x3803108>,
<ElementFormDefat0x3803248>,
<ElementFormDefat0x38036c8>,
<ElementItemGroupDefat0x38032c8>,
<ElementItemGroupDataat0x38035c8>,
<ElementClinicalDataat0x3803408>,

【讨论】:

    猜你喜欢
    • 2012-10-24
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    • 2014-06-15
    • 1970-01-01
    • 2018-01-07
    相关资源
    最近更新 更多