使用空 findall 结果枚举

Enumerate with empty findall result

提问人:Fey010 提问时间:5/5/2023 更新时间:5/5/2023 访问量:46

问:

我有一个 xml 文件,我想从中计算一些名为“neighbor”的标签。更具体地说,我只想计算邻居标签,它们是任何国家标签的直接子标签。

以下是我的 xml 文件的内容:

<?xml version="1.0"?>
<data>
    <country name="Austria">
        <rank>1</rank>
        <year>2008</year>
        <neighbor name="Liechtenstein"/>
        <neighbor name="Switzerland"/>
        <neighbor name="Italy"/>
    </country>
    <country name="Iceland">
        <hasnoneighbors/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <neighbor name="Malaysia"/>
        <someothertag>
             <neighbor name="Germany"/>
        </someothertag>
    </country>
    <neighbor name="Jupiter"/>
    <country name="Panama">
        <rank>68</rank>
        <year>2011</year>
        <neighbor name="Costa Rica"/>
        <neighbor name="Colombia"/>
        <country name="SubCountry">
            <rank>12</rank>
            <year>2023</year>
            <neighbor name="NeighborOfSubCountry"/>
        </country>
    </country>
</data>

预期结果应为 7。德国和木星应该被排除在总共 9 个标签之外。

我写了下面一段代码:

import xml.etree.ElementTree as ET
tree = ET.parse('test.xml')
root = tree.getroot()

totalneighbors = 0
neighborlist = []

for country in root.iter('country'):
    print(f'Country {country.attrib["name"]} contains these neighbors:')
    for index, neighbor in enumerate(country.findall('neighbor')):
        neighborname = neighbor.attrib['name']
        print(f'neighbor no {index+1}, with name {neighbor.attrib["name"]}')
        neighborlist.append(neighbor.attrib['name'])
    print(f"total for this country is {index+1}\n")
    totalneighbors += index+1

print(f'total nr of neighbors in country-nodes is {totalneighbors} according to index-counting')
print(f"but the neighborlist says it's {len(neighborlist)}")

我想使用 python 的枚举功能计算标签,但它给了我错误的结果(10 而不是 7)。我在代码中采用了另一种计数方法,将“findall”结果添加到列表中,然后使用该列表的长度。这确实给了我正确的数字。

在代码中添加了一些打印语句后,我弄清楚了哪里出了问题;冰岛没有邻居,但 print-statement 显示该指数仍为 3。看起来好像上一个循环中的索引从未被重置,它只是再次使用那个 3,即使“findall”应该什么也找不到。

所以我的问题是:我做错了什么?为什么当“findall”一无所获时,“enumerate”不给我 0?我用错了吗?还是与空搜索结果结合使用时是不可能的?

我希望有人能澄清这里出了什么问题。

python xml for 循环 枚举 findall

评论


答:

0赞 DasaniT 5/5/2023 #1

正如你所说,问题在于冰岛没有邻居。第一个国家/地区有三个邻居,因此在运行第一个循环后,其值为 2。但是该循环不会对冰岛执行,因为findall返回一个空列表。因此,该值仍将具有前一个国家/地区的值。indexforindex

您可以在循环之前设置 to。这样,您的代码就可以正常工作。因为如果该国没有邻居,则不会添加任何内容。index-1fortotalneighbors

# ...
print(f'Country {country.attrib["name"]} contains these neighbors:')
index = -1
for index, neighbor in enumerate(country.findall('neighbor')):
# remiander of the code

但总的来说,我建议使用软件包和 XPath。 在这里,您可以找到文档:https://lxml.de/parsing.htmllxml

出于您的目的,使用 XPath 是最佳选择。您可以在此处找到更多信息:https://www.w3schools.com/xml/xpath_intro.asp

使用的代码如下所示:lxml

from lxml import etree

root = etree.parse("/path/to/file.xml")
neighbors = root.findall(".//country/neighbor") # this xpath finds all the neighbors exactly after country

希望这会有所帮助。

评论

0赞 Fey010 5/5/2023
是的,我知道问题出在哪里,我也在问题描述中解释了这一点。感谢您建议使用“.//country/neighbor”(顺便说一句,它甚至不需要 lxml)。问题是,我使用遍历每个国家并收集其邻居孩子来创建字典的例行公事。如果能够使用 enumerate 同时对它们进行计数,那将会很有帮助。但是,如果返回空列表,也许这根本不可能,我将不得不使用单独的命令进行计数。
0赞 DasaniT 5/5/2023
@Fey010我推荐的,因为我有很好的使用经验,而不仅仅是因为 XPath。如果要使用 ,可以将 设置为 在循环之前。我认为这样你的代码就可以正常工作。lxmlindex-1forenumerate
0赞 Fey010 5/5/2023
谢谢伙计。在开始循环之前设置一个值为我修复了它!也许您可以编辑原始答案以包含此解决方案。这样我就可以选择它作为我问题的解决方案。