提取 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