【发布时间】:2018-04-18 10:02:22
【问题描述】:
我正在尝试遍历我只对某些元素值/文本感兴趣的嵌套 xml 文件结构。 xml itelf 包含“Row”元素,表示值可以出现多次。目标是将其读取/转换为数据库记录。 xml 看起来像这样:
<CommandManagerResults>
<ListPropertiesAttribute>
<Row>
<Name>AttributeName</Name>
<Id>B31BEF954E05B473A8D3A1B63B29F91E</Id>
<Description>TECHCOLUMNNAME</Description>
<LongDescription/>
<CreationTime>26. August 2010 10:16:10 MESZ</CreationTime>
<ModificationTime>23. November 2017 20:13:37 MEZ</ModificationTime>
<Owner>Administrator</Owner>
<Hidden>False</Hidden>
<Row>
<AttributeFormName>ID</AttributeFormName>
<AttributeFormCategory>ID</AttributeFormCategory>
<AttributeFormType>Number</AttributeFormType>
<AttributeFormDescription/>
<AttributeFormReportSort>None</AttributeFormReportSort>
<AttributeFormBrowseSort>None</AttributeFormBrowseSort>
<AttributeLookUpTable>FACT_TABLE_NAME</AttributeLookUpTable>
<Row>
<SchemaExpression>ApplySimple("nvl(#0, -2)";TECHCOLUMNNAME)</SchemaExpression>
<MappingMethod>Manual</MappingMethod>
<Row>
<SchemaCandidateTable>FACT_TABLE_NAME</SchemaCandidateTable>
</Row>
</Row>
<Multilingual>Unknown</Multilingual>
</Row>
<Row>
<AttributeFormName>DESC</AttributeFormName>
<AttributeFormCategory>DESC</AttributeFormCategory>
<AttributeFormType>Number</AttributeFormType>
<AttributeFormDescription/>
<AttributeFormReportSort>None</AttributeFormReportSort>
<AttributeFormBrowseSort>None</AttributeFormBrowseSort>
<AttributeLookUpTable>FACT_TABLE_NAME</AttributeLookUpTable>
<Row>
<SchemaExpression>TECHCOLUMNNAME</SchemaExpression>
<MappingMethod>Manual</MappingMethod>
<Row>
<SchemaCandidateTable>FACT_TABLE_NAME</SchemaCandidateTable>
</Row>
</Row>
<Multilingual>False</Multilingual>
</Row>
<Row>
<AttributeChild>TABLE_PK</AttributeChild>
<AttributeChildRelationship>One to Many</AttributeChildRelationship>
<AttributeChildTable>FACT_TABLE_NAME</AttributeChildTable>
<Path>\Schema Objects\Attributes\FACT_TABLE_NAME\Star Attributes\_technical</Path>
</Row>
<Row>
<Row>
<AttributeBrowseDisplay>DESC</AttributeBrowseDisplay>
</Row>
<Row>
<ReportDisplayForm>DESC</ReportDisplayForm>
</Row>
<AttributeElementDisplay>Locked</AttributeElementDisplay>
<SecurityFliterToElementBrowsing>True</SecurityFliterToElementBrowsing>
<EnableElementCaching>True</EnableElementCaching>
</Row>
</Row>
</ListPropertiesAttribute>
当把它写成一个程序脚本(我猜不是太 Pythonic)时,一切都按预期工作,但我必须一遍又一遍地重复编写相同的代码:
from lxml import etree
xml = "starattribute_multi.xml"
elem = etree.parse(xml).find("ListPropertiesAttribute")
l=[]
for r in elem.find(".//Row"):
if r.tag == 'Name':
_name = r.text
elif r.tag == "Id":
_id = r.text
elif r.getchildren():
for r1 in r:
if r1.tag == "AttributeFormName":
_attr_form = r1.text
elif r1.tag == "AttributeFormType":
_attr_form_type = r1.text
elif r1.tag == "AttributeFormReportSort":
_form_repsort = r1.text
elif r1.tag == "AttributeFormBrowseSort":
_form_browsesort = r1.text
elif r1.tag == "AttributeLookUpTable":
_attr_lutable = r1.text
elif r1.getchildren():
for r2 in r1:
if r2.tag == "SchemaExpression":
_schema_expr = r2.text
elif r2.tag == "MappingMethod":
_schema_mapping = r2.text
elif r2.getchildren():
for r3 in r2:
if r3.tag == "SchemaCandidateTable":
_schema_table = r3.text
l.append((_name,_id,_attr_form,_attr_form_type,_form_repsort,_form_browsesort,_attr_lutable,_schema_expr,_schema_mapping,_schema_table))
这一切都很好,我得到了我想要的元组列表。 输出如下:
[('AttributeName',
'B31BEF954E05B473A8D3A1B63B29F91E',
'ID',
'Number',
'None',
'None',
'FACT_TABLE_NAME',
'ApplySimple("nvl(#0, -2)";TECHCOLUMNNAME)',
'Manual',
'FACT_TABLE_NAME'),
('AttributeName',
'B31BEF954E05B473A8D3A1B63B29F91E',
'DESC',
'Number',
'None',
'None',
'FACT_TABLE_NAME',
'TECHCOLUMNNAME',
'Manual',
'FACT_TABLE_NAME')]
现在我想稍微正式化一下,以删除我的重复代码并允许我处理其他类似但不相同的 xml。 我想到了编写函数,它可以检查搜索元组中提供的我想要的标签并希望使用字典,以便稍后识别已找到的值。
我的函数如下所示:
def traverse3(xmlelement,searchelements,dictreturn):
_d=dict()
for row in xmlelement:
if row.getchildren():
traverse3(row,searchelements,_d)
else:
dictreturn[row.tag]=row.text
dictreturn.update(_d)
return dictreturn
当时的预期用途是:
from lxml import etree
root = etree.parse("some.xml")
l = []
tags = ('Name', 'Id', 'AttributeFormName', 'AttributeFormType', 'AttributeFormReportSort', 'AttributeFormBrowseSort', 'AttributeLookUpTable', 'SchemaExpression', 'MappingMethod','SchemaCandidateTable')
d = {}
l.append(traverse3(elem,tags,d))
我只得到了“最后一个”记录,这肯定是因为我错过了在某处添加一个新的 dict 或早点返回它或我错过的其他任何东西。
[{'Name': 'AttributeName',
'Id': 'B31BEF954E05B473A8D3A1B63B29F91E',
'Description': 'TECHCOLUMNNAME',
'AttributeFormName': 'DESC',
'AttributeFormType': 'Number',
'AttributeFormReportSort': 'None',
'AttributeFormBrowseSort': 'None',
'AttributeLookUpTable': 'FACT_TABLE_NAME',
'SchemaExpression': 'TECHCOLUMNNAME',
'MappingMethod': 'Manual',
'SchemaCandidateTable': 'FACT_TABLE_NAME']
添加一些打印后,我可以看到我想要的记录(带有 ID 表单的记录)在我的递归调用期间存在,但它被另一个与 DESC 表单有点相似的记录覆盖 - 我想要嗯,当然。 我添加了一些功能,试图减少我的搜索标签列表以具有某种退出条件,但是所有这样做的尝试(甚至移动返回)都以一些“NoneType 不可迭代”结束。
我真的很感激一些想法/方向。
提前为这个史诗般的问题/示例道歉。
【问题讨论】: