对于etree对象的所有元素的简单循环?

时间:2012-05-17 12:59:37

标签: python lxml

我有一个函数可以从etree元素返回一个列表,但它不会查看嵌套元素。

<elem>
    <variable id="getthis">
        <!-- / -->
    </variable>
    <if>
        <variable id="alsoGetThis">
            <!-- Keep looping through all elements -->
        </variable>
    </if>
</elem>

(我正在使用Valid XML

所以目前忽略了<if>中的变量,那么如何循环遍历树的所有层次?我假设这是一项简单的任务,但也许我错了。 (我是Python的新手,并且总是像程序员一样思考)

Python func获取变量:

def collect_vars(self, elem):
    elemVars = []
    if elem.tag == 'variable':
        elemVars.append(elem.attrib['id'])
    elif e in elem == 'variable': # don't want to be doing these
        elemVars.append(e.attrib['id'])
    return elemVars

所以我想最终得到的是包含给定elemVars

中所有变量ID的列表<elem>

2 个答案:

答案 0 :(得分:4)

考虑学习XPath并使用LXML的xpath成员。假设您的XML树名为t,就像您发布了

一样
>>> s = """<elem>
    <variable id="getthis">
        <!-- / -->
    </variable>
    <if>
        <variable id="alsoGetThis">
            <!-- Keep looping through all elements -->
        </variable>
    </if>
</elem>
"""
>>> t = etree.fromstring(s)

然后你可以用

找到树中的所有元素
>>> t.xpath("//*")
[<Element elem at 0x2809b40>, <Element variable at 0x2809be0>, <Element if at 0x2809af0>, <Element variable at 0x2809c80>]

以及

的所有variable元素
>>> t.xpath("//variable")
[<Element variable at 0x2809be0>, <Element variable at 0x2809c80>]

xpath返回满足您指定的XPath条件的元素列表,表示为元素树:

>>> [x.attrib["id"] for x in t.xpath("//variable")]
['getthis', 'alsoGetThis']

答案 1 :(得分:1)

您遇到的问题是您没有访问文件中的所有节点。您只访问elem元素的子元素,但您没有访问这些元素的子元素。为了说明这一点,运行以下内容(我已将您的XML编辑为有效):

from xml.etree.ElementTree as etree

xml_string = """<elem>
    <variable id="getthis" />
    <if>
        <variable id="alsoGetThis" />
    </if>
    </elem>"""

e = etree.fromstring(xml_string)

for node in e:
    print node

结果

<Element variable at 7f53fbdf1cb0>
<Element if at 7f53fbdf1cf8>

因此,您没有访问节点variable的子if。您将需要递归访问XML文件中的每个节点,即您的函数collect_vars将需要调用自身。我会稍微发布一些代码来说明这一点。

编辑:正如所承诺的,有些代码可以从元素树中获取所有id属性。我没有使用蓄能器作为Niek de Klein,而是使用了发电机。这具有许多优点。例如,这会一次返回id个,因此您可以在任何时候停止处理,例如,遇到某个id,这样可以节省读取整个XML文件的时间。< / p>

def get_attrs(element, tag, attr):
    """Return attribute `attr` of `tag` child elements of `element`."""

    # If an element has any cildren (nested elements) loop through them:
    if len(element):
         for node in element:
            # Recursively call this function, yielding each result:
            for attribute in get_attrs(node, tag, attr):
                yield attribute

    # Otherwise, check if element is of type `tag` with attribute `attr`, if so
    # yield the value of that attribute.
    if element.tag == 'variable':
        if attr in element.attrib:
            yield element.attrib[attr]

ids = [id for id in get_attrs(e, 'variable', 'id')]

print ids

产生结果

 ['getthis', 'alsoGetThis']