如何从带自闭合标签的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对象,但无法获取与之关联的文本信息,需要解决文本提取问题。
解决方案
你的代码存在两个核心问题:
page.findall('.//lb')是从<pb>节点向下查找<lb>,但实际<lb>并不是<pb>的子节点,而是和<pb>同属<ab>的后代,循环后liste_text只会保留最后一个页面的<lb>节点。- 目标文本并不是
<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
相关产品推荐
相关产品推荐

