我可以取消引用lxml.etree.AncestorsIterator吗?

时间:2016-07-07 08:34:04

标签: python lxml

我正在使用lxml来操作在xml文件中表示的dbschema。它看起来像这样:

<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")

我不喜欢这个解决方案,因为我知道我的名字命令只能迭代一个元素 - 它只有一个父“Table”。似乎在python中我只能在循环中使用迭代器。但我发现它有点傻。我知道我只有一个祖先“桌子”。我可以直接以某种方式取消引用迭代器吗?或者是否有另一种方法可以获得更合适的信息?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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'))