2016-07-07 89 views
1

我正在使用lxml来处理在xml文件中表示的dbschema。它看起来像这样:我可以取消引用lxml.etree.AncestorsIterator吗?

<Tables> 
<Table name = "table1"> 
<Columns> 
<Column name="COL1">...</Column> 
<Column name="COL2">... 
    <References> 
    <Reference>TABLENAME</Reference> 
    </References> 
</Column> 
</Table> 
... 
</Tables> 

当前我想查看引用,并获取这些引用的表和列名称。以下作品:

refiter = mytree.iter("Reference") 
for r in refiter: 
    nameiter =r.iterancestors("Table") 
    for n in nameiter: 
     tablename = .get("name") 

我不喜欢这样的解决方案,因为我知道我的nameiter只能遍历一个元素 - 它只有一个父“表”。看来在Python中我只能在循环中使用迭代器。但我觉得有点傻。我知道我只有一个祖先“表”。我可以直接取消引用迭代器吗?或者是否有另外一种方法来获取这种更适合的信息?

+0

我不太明白你想要什么,什么是*可我取迭代器直接不知何故?*是什么意思? ''//引用/祖先::表/ @名称| //引用/祖先::列/ @名称“)'会在单个查询中得到表名和列名 –

+0

我的母语是C++,所以当我错误地使用了另一种语言的词汇,我倾向于使用C++的单词,并希望它们以可理解的方式进行映射。在C++中,如果我有第一个元素的迭代器,我可以'derefrence' - 访问这个迭代器直接指向的对象,所以我可以跳过循环遍历的循环,我尝试了你的查询,但是恐怕它的正确用法超出了我的意思,我得到了所有表和列名的列表 – Spacemoose

+0

您是否想要删除名称中'for n的需要?刚刚获取以前的表名和列名?可能某些有效的输入和预期的输出会使它更清晰一些。 –

回答

0

您可以使用XPath来同时获得你想要

x = """<?xml version="1.0" encoding="utf-8"?> 
<Tables> 
<Table name = "table1"> 
<Columns> 
<Column name="COL1">...</Column> 
<Column name="COL2">... 
    <References> 
    <Reference>TABLENAME</Reference> 
    </References> 
</Column> 
</Columns> 
</Table> 
<Table name = "table2"> 
<Columns> 
<Column name="COL2">...</Column> 
<Column name="COL3">... 
    <References> 
    <Reference>TABLENAME</Reference> 
    </References> 
</Column> 
</Columns> 
</Table> 
</Tables>""" 


import lxml.etree as et 

xml = et.fromstring(x) 

refs = xml.iter("Reference") 
print([(ref.xpath("./ancestor::Table/@name")[0], ref.xpath("./ancestor::Column/@name")[0]) for ref in refs]) 

这将使你的祖先做:

[('table1', 'COL2'), ('table2', 'COL3')] 

或者列始终是祖父母:

[(ref.xpath("./ancestor::Table/@name")[0], ref.xpath("./../../@name")[0]) for ref in refs] 

使用你自己的逻辑,你可以在iterancetors上调用next:

refs = xml.iter("Reference") 


for r in refs: 
    print(next(r.iterancestors("Table")).get("name")) 
    print(next(r.iterancestors("Column")).get("name")) 

这将使你:

table1 
COL2 
table2 
COL3 
0

正如你所感兴趣的只是迭代器的第一个结果,你可以使用next方法来获得的第一个元素,并避免不清楚/不必要for循环。

xml_string = """ 
<Tables> 
<Table name = "table1"> 
<Columns> 
<Column name="COL1">...</Column> 
<Column name="COL2">... 
    <References> 
    <Reference>TABLENAME</Reference> 
    </References> 
</Column> 
</Columns> 
</Table> 
<Table name = "table2"> 
<Columns> 
<Column name="COL2">...</Column> 
<Column name="COL3">... 
    <References> 
    <Reference>TABLENAME</Reference> 
    </References> 
</Column> 
</Columns> 
</Table> 
</Tables>""" 


import lxml.etree as ETree 

root = ETree.fromstring(bytes(xml_string, 'UTF-8')) 

refiter = root.iter('Reference') 
for r in refiter: 
    nameiter = r.iterancestors('Table') 
    name = next(nameiter).get('name') 
    print(name) 

如果您想按索引访问结果,可以先从迭代器中生成一个列表。

tables = list(r.iterancestors('Table')) 
print(tables[0].get('name'))