【问题标题】:Control search depth findall Lxml控制搜索深度 findall Lxml
【发布时间】:2026-01-04 06:50:01
【问题描述】:

我是 Python 的初学者,并尝试在 Python 中使用 LXML 解析 XML。我正在尝试使用 finall() 搜索标签,但希望控制可以搜索标签但搜索不超过一个级别的深度。解释如下:

<?xml version='1.0' encoding='utf-8'?>
<system xmlns="some_name_space">
<a>
    <host>Random Name</host>
    <class>
        <name>Main_Tag_1</name>
        <detail>
            <name>Child_Tag_1</name>
            <ip>ip_1</ip>
            <port>port_1</port>
        <detail>
    </class>
    <class>
        <name>Main_Tag_2</name>
        <detail>
            <name>Child_Tag_2</name>
            <ip>ip_2</ip>
            <port>port_2</port>
        <detail>
    </class>
    <class>
        <name>Main_Tag_3</name>
        <detail>
            <name>Child_Tag_3</name>
            <ip>ip_3</ip>
            <port>port_3</port>
        <detail>
    </class>
</a>

我正在使用以下 python 来查找与 name 共享相同标记名的 所有 Main_tags。我没有在这里添加完整的程序。但是这个函数是类的一部分。

def name_ip_dict(self,filename):
self.tag_replace = {}
context = ET.iterparse(filename, tag='{some_name_space}class')
for action,elem in context:
    name_tag = elem.findall(".//{some_name_space}name")
    for name in name_tag: 
        print name.text
        for node in elem:
            ip_list = node.findall(".//{some_name_space}ip") 
            for ip in ip_node_list:
                self.tag_replace.setdefault(name.text, []).append(ip.text)

现在,我得到的输出是

{'Main_Tag_1': ['ip_1'], 'Child_tag_1': ['ip_1'], 'Main_Tag_2': ['ip_2'], 'Child_tag_1': ['ip_2']} and so on..

但我只想获取 First Parent,即 Main_Tag1,2 或 3 以及 ip 标签中的文本。

{'Main_Tag_1': ['ip_1'], 'Main_Tag_2': ['ip_2']} and so on..

这让我觉得有必要控制 findall 的深度,但我无法在网络上找到任何与深度相关的内容。

如果已经有这样的用例,请告诉我,实现这一目标的最佳方法是什么。

【问题讨论】:

    标签: python xml xml-parsing lxml


    【解决方案1】:

    如果您只想在直接子元素(不包括孙子和更深的后代元素)中搜索,请使用单斜杠 (/):

    name_tag = elem.findall("./{some_name_space}name")
    

    请注意,当您需要支持更高级的 XPath 表达式时,请使用 lxmlxpath() 方法而不是 findall()。后者只支持非常limited set 的XPath 表达式。

    【讨论】:

    • 感谢@har07 的建议,我会探索它。你给出的解决方案是完美的!
    • 可能有点断章取义。但是如何在 findall 中搜索多个标签。我在网上阅读它,似乎 findall("./{some_name_space}(tag1|tag2))" 应该可以工作,但它对我有用。因此,请检查专家建议。
    最近更新 更多