You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从带自闭合标签的TEI XML文件中提取文本内容?

问题描述

我有一批包含文档转录内容的TEI格式XML文件,希望解析这些文件并提取纯文本信息。

XML示例

<?xml version='1.0' encoding='UTF8'?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0">
  <text>
    <body>
      <ab>
        <pb n="page1"/>
          <cb n="1"/>
            <lb xml:id="DD1" n="1"/>my sentence 1
            <lb xml:id="DD2" n="2"/>my sentence 2
            <lb xml:id="DD3" n="3"/>my sentence 3
          <cb n="2"/>
            <lb xml:id="DD1" n="1"/>my sentence 4
            <lb xml:id="DD2" n="2"/>my sentence 5
        <pb n="page2"/>
          <cb n="1"/>
            <lb xml:id="DD1" n="1"/>my sentence 1
            <lb xml:id="DD2" n="2"/>my sentence 2
          <cb n="2"/>
            <lb xml:id="DD1" n="1"/>my sentence 3
            <lb xml:id="DD1" n="2"/>my sentence 4
      </ab>
    </body>
  </text>
</TEI>

尝试的代码

with open(file,'r') as my_file:
    
    root = ET.parse(my_file, parser = ET.XMLParser(encoding = 'utf-8'))
    list_pages = root.findall('.//{http://www.tei-c.org/ns/1.0}pb')
    for page in list_pages:
        liste_text = page.findall('.//{http://www.tei-c.org/ns/1.0}lb')
    
    final_text = []
    
    for content in liste_text:
        final_text.append(content.text)

期望输出

page1
my sentence 1
my sentence 2
my sentence 3
my sentence 4
my sentence 5
page2
my sentence 1
my sentence 2
my sentence 3
my sentence 4

目前能成功获取lb对象,但无法获取与之关联的文本信息,需要解决文本提取问题。


解决方案

你的代码存在两个核心问题:

  1. page.findall('.//lb')是从<pb>节点向下查找<lb>,但实际<lb>并不是<pb>的子节点,而是和<pb>同属<ab>的后代,循环后liste_text只会保留最后一个页面的<lb>节点。
  2. 目标文本并不是<lb>元素的text属性,而是<lb>的下一个兄弟文本节点(<lb>是空元素,文本紧跟在它后面)。

修正后的代码如下:

from lxml import etree as ET

NS = {'tei': 'http://www.tei-c.org/ns/1.0'}
final_output = []

with open(file, 'r') as my_file:
    root = ET.parse(my_file, parser=ET.XMLParser(encoding='utf-8'))
    # 获取包含所有内容的ab节点
    ab_node = root.find('.//tei:ab', namespaces=NS)
    
    # 遍历ab下的所有节点,区分页面标记、行标记和文本
    for node in ab_node:
        if node.tag == f'{{{NS["tei"]}}}pb':
            # 添加页面编号
            final_output.append(node.get('n'))
        elif node.tag == f'{{{NS["tei"]}}}cb':
            # 跳过列标记节点
            continue
        elif node.tag == f'{{{NS["tei"]}}}lb':
            # 提取lb后的文本,去除首尾空白
            text = node.tail.strip() if node.tail else ''
            if text:
                final_output.append(text)
        # 处理其他节点后的零散文本
        elif node.tail:
            tail_text = node.tail.strip()
            if tail_text:
                final_output.append(tail_text)

# 输出最终结果
print('\n'.join(final_output))

代码说明

  • 使用命名空间映射简化节点查询,避免重复书写冗长的命名空间字符串。
  • 直接遍历<ab>节点下的所有子节点,遇到<pb>时提取其n属性作为页标题;遇到<lb>时提取其tail属性(即元素后方的文本内容)。
  • 跳过<cb>列标记节点,仅保留需要的页面和句子文本。
  • 对文本做strip()处理,清除多余的空白字符。

运行该代码后,即可得到你期望的输出格式。

内容的提问来源于stack exchange,提问作者hedone5628

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:30:58