提问人:Serge Kashlik 提问时间:10/16/2023 更新时间:10/17/2023 访问量:51
XML 解析:如何返回 None is not found 元素
XML parsing: how to return None is element was not found
问:
我需要解析一个 XML 文件,其中同一标记可能存在不同数量的子项,如下所示:
xml_file = '''
<clients>
<client>
<name>John</name>
</client>
<client>
<name>Mike</name>
<age>25</age>
</client>
</clients>
'''
如果未找到任何标签,我希望代码返回。我目前的解决方案如下所示:None
from xml.etree import ElementTree as et
tree = et.fromstring(xml_file)
client_attr = []
for client in tree.iter('client'):
results = {'name': None, 'age': None}
name = client.find('name')
age = client.find('age')
results.update({
'name': name.text if name is not None else None,
'age': age.text if age is not None else None
}
)
client_attr.append(results)
然而,这似乎有点笨拙,当应用于我的真实数据时,会占用大量的空间和时间。在我看来,应该有一种方法可以组合这些步骤,但我无法弄清楚如何。 提前谢谢。
答:
乍一看,为了实现您希望实现的行为,您必须考虑将会出现的其他一些问题,这些问题您可能已经考虑过,但可惜的是,您似乎没有在发布的查询中指定您计划如何进行它们。
例如,正如您在注释中澄清的那样,您想要代码,我认为这是函数的一部分,因为如果不是,您就不可能返回 None 或查询中显示状态的任何值;如果找到未指定年龄的标签,您希望它返回 None,这引发了有关其余数据的问题,这意味着,您将如何处理到目前为止处理的内容,您是否打算简单地丢弃它?然后是关于您将如何通知用户有关差异的问题,以及最终您将采取什么措施来解决问题。
这可能会导致一个更复杂的解析系统,但它仍然更健壮,并且总体上试图明智地利用系统的资源。
尽管如此,如果这不是您打算通过代码实现的目标,那么我将简单地建议:
a) 将代码包装到一个函数中,如果希望在找不到 age 或 name 时返回 None,即当函数返回 None 时,则这样做,并且循环不会继续,从而将时间整体切片,除了格式错误的元素是最后一个元素的最坏情况;
b) 在发生异常时引发异常,以便调用方适当地处理它,这可能需要通知用户文件不遵守格式规则等。为此,etree有一个例外。find
ParseError
现在,要记住的一件事是,None 是模棱两可的,因为它可以代表任何东西,并且为了让某人知道在这种情况下它代表没有 age child 标签,这将意味着该特定的人熟悉代码,和/或文档正在描述这种行为, 并且隐含地表示,每个处理代码的人都在阅读上述文档。
在这种情况下,由于代码的编写方式,我建议使用异常方法解决上述歧义,另一种方法是返回一个类型,该类型要么保存值,在本例中为字典,要么,这将在某种程度上使您能够返回数据,直到它是正确的点, 如果第一个元素已经有故障,则为 None。Optional
Some
None
此外,您实际上不需要调用,因为您可以直接将值分配给字典,这也可能稍微提高代码的效率。update
如果可以使用 pandas:
import pandas as pd
import numpy as np
xml_file = '''
<clients>
<client>
<name>John</name>
</client>
<client>
<name>Mike</name>
<age>25</age>
</client>
</clients>
'''
df = pd.read_xml(xml_file, xpath = './/client')
print(df.replace(np.nan, None))
如果没有 numpy 和 replace 函数,pandas 将显示 NaN。
name age
0 John None
1 Mike 25.0
评论
另一种解决方案,使用:beautifulsoup
import pandas as pd
from bs4 import BeautifulSoup
xml_file = """
<clients>
<client>
<name>John</name>
</client>
<client>
<name>Mike</name>
<age>25</age>
</client>
</clients>
"""
soup = BeautifulSoup(xml_file, "xml")
all_data = []
for client in soup.select("client"):
all_data.append(
{
t.name: t.get_text(strip=True, separator=" ")
for t in client.find_all(recursive=False)
}
)
df = pd.DataFrame(all_data)
print(df)
指纹:
name age
0 John NaN
1 Mike 25
评论
None
client
clients
client
age