解析 Python 中的大型复杂专利分类 XML 文件
Parsing a large complicated patent classification XML file in Python
我正在尝试解析一个大文件,尤其是 https://www.wipo.int/ipc/itos4ipc/ITSupport_and_download_area/20200101/MasterFiles/index.html 的英文版,XML 格式的专利分类。我是 XML 解析的新手,所以我认为这就是为什么我很难从这个文件中解析我真正想要的元素的原因。
让我提供一些背景信息:
<?xml version="1.0" encoding="UTF-8"?>
<IPCScheme xmlns="http://www.wipo.int/classifications/ipc/masterfiles" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" edition="20200101" lang="EN" xsi:schemaLocation="http://www.wipo.int/classifications/ipc/masterfiles ipc_scheme_3-1.xsd">
<ipcEntry kind="s" symbol="A" entryType="K">
<textBody>
<title>
<titlePart>
<text>HUMAN NECESSITIES</text>
</titlePart>
</title>
</textBody>
<ipcEntry kind="t" symbol="A01" endSymbol="A01" entryType="K">
<textBody>
<title>
<titlePart>
<text>AGRICULTURE</text>
</titlePart>
</title>
</textBody>
</ipcEntry>
<ipcEntry kind="c" symbol="A01" entryType="K">
<textBody>
<title>
<titlePart>
<text>AGRICULTURE</text>
</titlePart>
<titlePart>
<text>FORESTRY</text>
</titlePart>
<titlePart>
<text>ANIMAL HUSBANDRY</text>
</titlePart>
<titlePart>
<text>HUNTING</text>
</titlePart>
<titlePart>
<text>TRAPPING</text>
</titlePart>
<titlePart>
<text>FISHING</text>
</titlePart>
</title>
</textBody>
.
.
</ipcEntry>
.
.
</IPCScheme>
你可以假设文件格式完美,每个分支都有完整的关闭。它相当长,大约有 800,000 行,这就是为什么我不在此代码示例中附加整个文件的原因。
层次结构的简短概述应该如下所示:
- 根目录
- 级别 1:符号 {A、B、C、D、E、F、K}
- 级别 2:每个符号中的细分 {A01、B22 等}
- 3 级:进一步细分
这一直持续到大约 H05K0013040000,最大的粒度复杂层。在其中一些中,它会停止到大约 5 级,但样本未关闭的原因是它们之间的这些进一步细分。
任务
我想从此专利分类文件中提取文本描述,例如在我想提取 HUMAN NECESSITIES
或 AGRICULTURE
的示例中。您可以假设所有这些细分都在其中,并且其中大部分都在这个级别上由这个层次结构支配(即 <title>
-> <titlePart>
-> <text>
)
在Python
中使用lxml
这是我一直在尝试做的示例代码:
from lxml import etree
import lxml
tree = etree.parse('EN_ipc_scheme_20200101.xml')
root = tree.getroot()
for elem in root.findall(".//*[@kind='s']"):
body = elem.find('textBody/title/titlePart/text')
print(body)
我的输出是
None
None
None
None
None
None
None
None
这可能有效:)
from lxml import etree
import lxml
tree = etree.parse('EN_ipc_scheme_20200101.xml')
root = tree.getroot()
for element in root.iter():
if element.text != None:
print("%s" % (element.text))
输出:
HUMAN NECESSITIES
AGRICULTURE
AGRICULTURE
FORESTRY
ANIMAL HUSBANDRY
HUNTING
TRAPPING
FISHING
SOIL WORKING IN AGRICULTURE OR FORESTRY
PARTS, DETAILS, OR ACCESSORIES OF AGRICULTURAL MACHINES OR IMPLEMENTS, IN GENERAL
making or covering furrows or holes for sowing, planting or manuring
machines for harvesting root crops
mowers convertible to soil working apparatus or capable of soil working
mowers combined with soil working implements
soil working for engineering purposes
... (continued very long had to interrupt)
尽管您可以将代码从在控制台上打印更改为保存在文本文件中。那将保存结果。可能需要一些时间才能全部写完。
您显示的 XML 示例中每个实体的名称空间都属于 xmlns="http://www.wipo.int/classifications/ipc/masterfiles"
。你可以通过查看 root 的 children 来看到这一点。
root.getchildren()
# returns:
[<Element {http://www.wipo.int/classifications/ipc/masterfiles}ipcEntry at 0x210f93ab288>]
花括号中的http路径为命名空间。要搜索,您必须指定要在其中搜索的名称空间。通常,您可以将命名空间的名称附加到路径元素的前面,并将命名空间作为字典传入,如下所示:
root.findall('xs:textBody', namespaces=ns)
问题在于此命名空间未标记,因此它出现在键 None
下的命名空间映射中。
root.nsmap
# returns:
{None: 'http://www.wipo.int/classifications/ipc/masterfiles',
'xhtml': 'http://www.w3.org/1999/xhtml',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
作为一个简单的 work-around,您可以将 None
键替换为您选择的键,然后在搜索中引用该键。下面,您可以将默认命名空间称为 'z'
.
ns = xml.nsmap
ns['z'] = ns.pop(None)
for elem in root.findall(".//*[@kind='s']", namespaces=ns):
body = elem.find('z:textBody/z:title/z:titlePart/z:text', namespaces=ns)
print(body.text)
# prints:
HUMAN NECESSITIES
或者,您可以在每个路径元素之前使用 {*}
搜索所有命名空间。
for elem in root.findall(".//*[@kind='s']"):
body = elem.find('{*}textBody/{*}title/{*}titlePart/{*}text')
print(body.text)
# prints:
HUMAN NECESSITIES
我正在尝试解析一个大文件,尤其是 https://www.wipo.int/ipc/itos4ipc/ITSupport_and_download_area/20200101/MasterFiles/index.html 的英文版,XML 格式的专利分类。我是 XML 解析的新手,所以我认为这就是为什么我很难从这个文件中解析我真正想要的元素的原因。
让我提供一些背景信息:
<?xml version="1.0" encoding="UTF-8"?>
<IPCScheme xmlns="http://www.wipo.int/classifications/ipc/masterfiles" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" edition="20200101" lang="EN" xsi:schemaLocation="http://www.wipo.int/classifications/ipc/masterfiles ipc_scheme_3-1.xsd">
<ipcEntry kind="s" symbol="A" entryType="K">
<textBody>
<title>
<titlePart>
<text>HUMAN NECESSITIES</text>
</titlePart>
</title>
</textBody>
<ipcEntry kind="t" symbol="A01" endSymbol="A01" entryType="K">
<textBody>
<title>
<titlePart>
<text>AGRICULTURE</text>
</titlePart>
</title>
</textBody>
</ipcEntry>
<ipcEntry kind="c" symbol="A01" entryType="K">
<textBody>
<title>
<titlePart>
<text>AGRICULTURE</text>
</titlePart>
<titlePart>
<text>FORESTRY</text>
</titlePart>
<titlePart>
<text>ANIMAL HUSBANDRY</text>
</titlePart>
<titlePart>
<text>HUNTING</text>
</titlePart>
<titlePart>
<text>TRAPPING</text>
</titlePart>
<titlePart>
<text>FISHING</text>
</titlePart>
</title>
</textBody>
.
.
</ipcEntry>
.
.
</IPCScheme>
你可以假设文件格式完美,每个分支都有完整的关闭。它相当长,大约有 800,000 行,这就是为什么我不在此代码示例中附加整个文件的原因。
层次结构的简短概述应该如下所示:
- 根目录
- 级别 1:符号 {A、B、C、D、E、F、K}
- 级别 2:每个符号中的细分 {A01、B22 等}
- 3 级:进一步细分
这一直持续到大约 H05K0013040000,最大的粒度复杂层。在其中一些中,它会停止到大约 5 级,但样本未关闭的原因是它们之间的这些进一步细分。
任务
我想从此专利分类文件中提取文本描述,例如在我想提取 HUMAN NECESSITIES
或 AGRICULTURE
的示例中。您可以假设所有这些细分都在其中,并且其中大部分都在这个级别上由这个层次结构支配(即 <title>
-> <titlePart>
-> <text>
)
在Python
中使用lxml
这是我一直在尝试做的示例代码:
from lxml import etree
import lxml
tree = etree.parse('EN_ipc_scheme_20200101.xml')
root = tree.getroot()
for elem in root.findall(".//*[@kind='s']"):
body = elem.find('textBody/title/titlePart/text')
print(body)
我的输出是
None
None
None
None
None
None
None
None
这可能有效:)
from lxml import etree
import lxml
tree = etree.parse('EN_ipc_scheme_20200101.xml')
root = tree.getroot()
for element in root.iter():
if element.text != None:
print("%s" % (element.text))
输出:
HUMAN NECESSITIES
AGRICULTURE
AGRICULTURE
FORESTRY
ANIMAL HUSBANDRY
HUNTING
TRAPPING
FISHING
SOIL WORKING IN AGRICULTURE OR FORESTRY
PARTS, DETAILS, OR ACCESSORIES OF AGRICULTURAL MACHINES OR IMPLEMENTS, IN GENERAL
making or covering furrows or holes for sowing, planting or manuring
machines for harvesting root crops
mowers convertible to soil working apparatus or capable of soil working
mowers combined with soil working implements
soil working for engineering purposes
... (continued very long had to interrupt)
尽管您可以将代码从在控制台上打印更改为保存在文本文件中。那将保存结果。可能需要一些时间才能全部写完。
您显示的 XML 示例中每个实体的名称空间都属于 xmlns="http://www.wipo.int/classifications/ipc/masterfiles"
。你可以通过查看 root 的 children 来看到这一点。
root.getchildren()
# returns:
[<Element {http://www.wipo.int/classifications/ipc/masterfiles}ipcEntry at 0x210f93ab288>]
花括号中的http路径为命名空间。要搜索,您必须指定要在其中搜索的名称空间。通常,您可以将命名空间的名称附加到路径元素的前面,并将命名空间作为字典传入,如下所示:
root.findall('xs:textBody', namespaces=ns)
问题在于此命名空间未标记,因此它出现在键 None
下的命名空间映射中。
root.nsmap
# returns:
{None: 'http://www.wipo.int/classifications/ipc/masterfiles',
'xhtml': 'http://www.w3.org/1999/xhtml',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}
作为一个简单的 work-around,您可以将 None
键替换为您选择的键,然后在搜索中引用该键。下面,您可以将默认命名空间称为 'z'
.
ns = xml.nsmap
ns['z'] = ns.pop(None)
for elem in root.findall(".//*[@kind='s']", namespaces=ns):
body = elem.find('z:textBody/z:title/z:titlePart/z:text', namespaces=ns)
print(body.text)
# prints:
HUMAN NECESSITIES
或者,您可以在每个路径元素之前使用 {*}
搜索所有命名空间。
for elem in root.findall(".//*[@kind='s']"):
body = elem.find('{*}textBody/{*}title/{*}titlePart/{*}text')
print(body.text)
# prints:
HUMAN NECESSITIES