相对python xml节点遍历

时间:2015-04-30 05:16:03

标签: python xml parsing

我很震惊,我可以使用VBA而不是python执行以下操作。我试图从api解析返回的xml为可用的格式。基于以下结构示例,这需要执行嵌套循环。麻烦的是最外面的循环从树中返回一个分离的元素,因此findall或iterfind什么也得不到,嵌套循环中止。我尝试使用3.4.1和2.7.8并获得相同的结果。这对我来说毫无意义。

import xml.etree.ElementTree as ET
data = """
<root>
    <c1>
        <c2>C2 Value 1</c2>
        <s1>
            <s2> S2 Value 1</s2>
            <p1>
                <p2>P2 Value 1</p2>
            </p1>
            <p1>
                <p2>P2 Value 2</p2>
            </p1>
        </s1>
        <s1>
            <s2> S2 Value 2</s2>
            <p1>
                <p2>P2 Value 3</p2>
            </p1>
        </s1>
    </c1>
</root>
"""
def use_et():
    doc = ET.fromstring(data)
    result = ['','','']
    for c in doc.findall('.//c2'):
        result[0] = c.text
        # nothing here executes
        # c is a detached Element. list(c) = []
        for s in c.findall('..//s2'):
            result[1] = s.text
            for p in s.iterfind('..//p2'):
                result[2] = p.text
                print(','.join(result))
use_et()

2 个答案:

答案 0 :(得分:2)

是的,来自xml.etree的行为似乎很奇怪。看起来它适用于第三方lxml模块,尽管我认为它仍然更快:

>>> import lxml.etree as ET
>>> doc = ET.fromstring(data)
>>> c = doc.find('.//c2')
>>> c
<Element c2 at 0x10bdc3ef0>
>>> c.findall('..//s2')
[<Element s2 at 0x10bdc8a28>, <Element s2 at 0x10bdc8950>]

答案 1 :(得分:1)

假设您正在寻找第一个值,您可以执行此操作而无需循环:

complete

结果:

import xml.etree.ElementTree as ET
data = """
<root>
    <c1>
        <c2>C2 Value 1</c2>
        <s1>
            <s2> S2 Value 1</s2>
            <p1>
                <p2>P2 Value 1</p2>
            </p1>
            <p1>
                <p2>P2 Value 2</p2>
            </p1>
        </s1>
        <s1>
            <s2> S2 Value 2</s2>
            <p1>
                <p2>P2 Value 3</p2>
            </p1>
        </s1>
    </c1>
</root>
"""
doc = ET.fromstring(data)
print ','.join(doc.findtext(_) for _ in ['.//c2', './/c2/../s1/s2', './/c2/../s1/p1/p2'])

+1在另一篇推荐lxml的帖子上,如果你需要更高级的东西,可以提供更好的xpath支持。