提取 xml 中的第一个元素 - 使用 xxx.find() 会导致非类型错误?
Extracting first element in xml - using xxx.find() leads to nonetype error?
xml-file 的结构基本上是这样的,它是 MARC21-xml 格式的书目数据(各地的图书馆都在使用):
<?xml version="1.0" encoding="UTF-8"?><collection xmlns="http://www.loc.gov/MARC21/slim">
<record type="Bibliographic">
<leader> ... </leader>
<controlfield> ... </controlfield>
...
<controlfield> ... </controlfield>
<datafield tag="123" ... >
<subfield code="x"> ... </subfield>
...
<subfield code="x"> ... </subfield>
</datafield>
<datafield tag="456" ...>
这里有一个合适的 example-file:https://www.loc.gov/standards/marcxml/Sandburg/sandburg.xml - 然而,这只代表一个项目(例如一本特定的书),通常这些文件包含成百上千条记录 - 所以记录标签其所有内容都是可重复的。
我使用的文件中有超过 10,000 个 record-tags(全部代表不同的项目),所有这些都有一个带有标签“082”的数据字段,然后是几个子字段。
我现在正尝试使用 code="a"
提取子字段中的文本 - 但是,由于该字段也是可重复的,并且某些记录有两个,所以我总是只想要第一个。我当前的代码提取这些数据字段中所有子字段 code="a"
的文本,如下所示:
for child in record.findall("{http://www.loc.gov/MARC21/slim}datafield[@tag='082']"):
for subelement in child:
if subelement.attrib['code'] == "a":
ddc = subelement.text
ddccoll.append(ddc)
这有效,但是,正如我所说,return 元素太多,如果我 运行 它然后打印我的列表的长度它 returns 10277,但是,此文件中只有 10123 条记录,所以可能是因为它的可重复性。
我尝试使用 find
而不是 findall
,但随后收到错误消息 `TypeError:
TypeError Traceback (most recent call last)
<ipython-input-23-fae786776bcf> in <module>
18 idcoll.append("nicht vorhanden")
19
---> 20 for child in record.find("{http://www.loc.gov/MARC21/slim}datafield[@tag='082']"):
21 for subelement in child:
22 if subelement.attrib['code'] == "a":
TypeError: 'NoneType' object is not iterable
我不确定为什么,因为字段 082 应该出现在每条记录中 - 但由于我实际上是在子字段之后,所以这可能不是正确的方法。现在,我尝试更深入一层,并使用以下代码简单地查找代码为 a 的第一个子元素:
for child in record.findall("{http://www.loc.gov/MARC21/slim}datafield[@tag='082']"):
for subelement in child.find("{http://www.loc.gov/MARC21/slim}subfield[@code='a']"):
if subelement:
ddc = subelement.text
ddccoll.append(ddc)
然而,这并没有 return resp。追加任何东西,如果我之后打印列表的长度,它会显示“0”。我也为作者和 id 做了同样的事情,它正在为那些人工作。我正在努力做到这一点,以便之后我可以创建一个包含作者、ID、标题等的 Dataframe
我现在完全卡在这个问题上了:是不是路径错了?还有其他更简单、更好的方法吗?
我假设您已经使用以下代码阅读了您的 XML:
import xml.etree.ElementTree as et
tree = et.parse('Input.xml')
root = tree.getroot()
要获得您想要的元素,您可以使用以下代码:
# Namespace dictionary
ns = {'slim': 'http://www.loc.gov/MARC21/slim'}
# Process "datafield" elements with the required "tag" attribute
for it in root.findall('.//slim:datafield[@tag="082"]', ns):
print(f'{it.tag:10}, {it.attrib}')
# Find the first child with "code" == "a"
child = it.find('slim:*[@code="a"]', ns)
if isinstance(child, et.Element): # Something found
print(f' {child.tag:10}, {child.attrib}, {child.text}')
else:
print(' Nothing found')
在上面的示例中,我只包含了元素的 print 语句
已找到,但您可以随心所欲地使用它们。
使用以下来源XML:
<?xml version="1.0" encoding="UTF-8"?>
<collection xmlns="http://www.loc.gov/MARC21/slim">
<record type="Bibliographic">
<leader>...</leader>
<controlfield>...</controlfield>
<datafield tag="082" id="1">
<subfield code="a">a1</subfield>
<subfield code="x">x1</subfield>
<subfield code="a">a2</subfield>
</datafield>
<datafield tag="456" id="2">
<subfield code="a">a3</subfield>
</datafield>
<datafield tag="082" id="3">
<subfield code="a">a4</subfield>
<subfield code="x">x2</subfield>
<subfield code="a">a5</subfield>
</datafield>
</record>
<record type="Bibliographic">
<leader>...</leader>
<controlfield>...</controlfield>
<datafield tag="082" id="4">
<subfield code="a">a6</subfield>
<subfield code="x">x3</subfield>
<subfield code="a">a7</subfield>
</datafield>
<datafield tag="456" id="5">
<subfield code="a">a8</subfield>
</datafield>
</record>
</collection>
我得到以下结果:
{http://www.loc.gov/MARC21/slim}datafield, {'tag': '082', 'id': '1'}
{http://www.loc.gov/MARC21/slim}subfield, {'code': 'a'}, a1
{http://www.loc.gov/MARC21/slim}datafield, {'tag': '082', 'id': '3'}
{http://www.loc.gov/MARC21/slim}subfield, {'code': 'a'}, a4
{http://www.loc.gov/MARC21/slim}datafield, {'tag': '082', 'id': '4'}
{http://www.loc.gov/MARC21/slim}subfield, {'code': 'a'}, a6
xml-file 的结构基本上是这样的,它是 MARC21-xml 格式的书目数据(各地的图书馆都在使用):
<?xml version="1.0" encoding="UTF-8"?><collection xmlns="http://www.loc.gov/MARC21/slim">
<record type="Bibliographic">
<leader> ... </leader>
<controlfield> ... </controlfield>
...
<controlfield> ... </controlfield>
<datafield tag="123" ... >
<subfield code="x"> ... </subfield>
...
<subfield code="x"> ... </subfield>
</datafield>
<datafield tag="456" ...>
这里有一个合适的 example-file:https://www.loc.gov/standards/marcxml/Sandburg/sandburg.xml - 然而,这只代表一个项目(例如一本特定的书),通常这些文件包含成百上千条记录 - 所以记录标签其所有内容都是可重复的。
我使用的文件中有超过 10,000 个 record-tags(全部代表不同的项目),所有这些都有一个带有标签“082”的数据字段,然后是几个子字段。
我现在正尝试使用 code="a"
提取子字段中的文本 - 但是,由于该字段也是可重复的,并且某些记录有两个,所以我总是只想要第一个。我当前的代码提取这些数据字段中所有子字段 code="a"
的文本,如下所示:
for child in record.findall("{http://www.loc.gov/MARC21/slim}datafield[@tag='082']"):
for subelement in child:
if subelement.attrib['code'] == "a":
ddc = subelement.text
ddccoll.append(ddc)
这有效,但是,正如我所说,return 元素太多,如果我 运行 它然后打印我的列表的长度它 returns 10277,但是,此文件中只有 10123 条记录,所以可能是因为它的可重复性。
我尝试使用 find
而不是 findall
,但随后收到错误消息 `TypeError:
TypeError Traceback (most recent call last)
<ipython-input-23-fae786776bcf> in <module>
18 idcoll.append("nicht vorhanden")
19
---> 20 for child in record.find("{http://www.loc.gov/MARC21/slim}datafield[@tag='082']"):
21 for subelement in child:
22 if subelement.attrib['code'] == "a":
TypeError: 'NoneType' object is not iterable
我不确定为什么,因为字段 082 应该出现在每条记录中 - 但由于我实际上是在子字段之后,所以这可能不是正确的方法。现在,我尝试更深入一层,并使用以下代码简单地查找代码为 a 的第一个子元素:
for child in record.findall("{http://www.loc.gov/MARC21/slim}datafield[@tag='082']"):
for subelement in child.find("{http://www.loc.gov/MARC21/slim}subfield[@code='a']"):
if subelement:
ddc = subelement.text
ddccoll.append(ddc)
然而,这并没有 return resp。追加任何东西,如果我之后打印列表的长度,它会显示“0”。我也为作者和 id 做了同样的事情,它正在为那些人工作。我正在努力做到这一点,以便之后我可以创建一个包含作者、ID、标题等的 Dataframe
我现在完全卡在这个问题上了:是不是路径错了?还有其他更简单、更好的方法吗?
我假设您已经使用以下代码阅读了您的 XML:
import xml.etree.ElementTree as et
tree = et.parse('Input.xml')
root = tree.getroot()
要获得您想要的元素,您可以使用以下代码:
# Namespace dictionary
ns = {'slim': 'http://www.loc.gov/MARC21/slim'}
# Process "datafield" elements with the required "tag" attribute
for it in root.findall('.//slim:datafield[@tag="082"]', ns):
print(f'{it.tag:10}, {it.attrib}')
# Find the first child with "code" == "a"
child = it.find('slim:*[@code="a"]', ns)
if isinstance(child, et.Element): # Something found
print(f' {child.tag:10}, {child.attrib}, {child.text}')
else:
print(' Nothing found')
在上面的示例中,我只包含了元素的 print 语句 已找到,但您可以随心所欲地使用它们。
使用以下来源XML:
<?xml version="1.0" encoding="UTF-8"?>
<collection xmlns="http://www.loc.gov/MARC21/slim">
<record type="Bibliographic">
<leader>...</leader>
<controlfield>...</controlfield>
<datafield tag="082" id="1">
<subfield code="a">a1</subfield>
<subfield code="x">x1</subfield>
<subfield code="a">a2</subfield>
</datafield>
<datafield tag="456" id="2">
<subfield code="a">a3</subfield>
</datafield>
<datafield tag="082" id="3">
<subfield code="a">a4</subfield>
<subfield code="x">x2</subfield>
<subfield code="a">a5</subfield>
</datafield>
</record>
<record type="Bibliographic">
<leader>...</leader>
<controlfield>...</controlfield>
<datafield tag="082" id="4">
<subfield code="a">a6</subfield>
<subfield code="x">x3</subfield>
<subfield code="a">a7</subfield>
</datafield>
<datafield tag="456" id="5">
<subfield code="a">a8</subfield>
</datafield>
</record>
</collection>
我得到以下结果:
{http://www.loc.gov/MARC21/slim}datafield, {'tag': '082', 'id': '1'}
{http://www.loc.gov/MARC21/slim}subfield, {'code': 'a'}, a1
{http://www.loc.gov/MARC21/slim}datafield, {'tag': '082', 'id': '3'}
{http://www.loc.gov/MARC21/slim}subfield, {'code': 'a'}, a4
{http://www.loc.gov/MARC21/slim}datafield, {'tag': '082', 'id': '4'}
{http://www.loc.gov/MARC21/slim}subfield, {'code': 'a'}, a6