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

XML文档中软件提及内容的<software>标签包裹实现问询

解决XML中

标签内软件名称的标签包裹问题

问题背景

  • XML文件中目标软件名称位于<p>标签内,且<p>标签通常包含<ref>等子标签
  • 需要将指定软件名称精准包裹在<software>标签中,简单文本替换无法满足定位需求
  • 已有JSON文件记录所有软件提及的位置信息(含字符偏移量、段落编号)
  • 尝试过xml.etree、Beautiful Soup、lxml等工具,现有脚本需完善

输入输出示例

输入XML片段

<p> The reliability of the model structure was tested using the ENERGY commands of MODELLER <ref type="bibr" target="#b45">(Sali and Blundell, 1993)</ref>. The modelled structures were also validated using the program PROSA <ref type="bibr" target="#b54">(Wiederstein and Sippl, 2007)</ref>.</p>

期望输出XML片段

<p> The reliability of the model structure was tested using the ENERGY commands of <software>MODELLER</software> <ref type="bibr" target="#b45">(Sali and Blundell, 1993)</ref>. The modelled structures were also validated using the program <software>PROSA</software> <ref type="bibr" target="#b54">(Wiederstein and Sippl, 2007)</ref>.</p>

软件标注JSON示例

{
    "type": "software",
    "software-type": "software",
    "software-name": {
        "rawForm": "MODELLER",
        "normalizedForm": "MODELLER",
        "offsetStart": 79,
        "offsetEnd": 87,
        "boundingBoxes": [
            {
                "p": 1,
                "x": 495.722,
                "y": 320.344,
                "w": 53.9323,
                "h": 8.0517
            }
        ]
    },
    "context": "The reliability of the model structure was tested using the ENERGY commands of MODELLER (Sali and Blundell, 1993)."
}

完善后的Python解决方案

使用lxml库处理XML节点的文本拆分与插入,利用JSON标注中的偏移量精准定位软件名称:

from lxml import etree
import json

def wrap_software_in_p(xml_content, software_annotations):
    # 解析XML,保留格式
    parser = etree.XMLParser(remove_blank_text=True)
    root = etree.fromstring(xml_content, parser)
    
    # 按段落索引处理(JSON中p字段为段落编号,从1开始)
    for idx, p_elem in enumerate(root.findall('.//p'), start=1):
        # 筛选当前段落的所有软件标注
        current_annos = [anno for anno in software_annotations 
                        if anno['software-name']['boundingBoxes'][0]['p'] == idx]
        if not current_annos:
            continue
        
        # 按偏移量降序排序,避免插入新节点影响后续偏移计算
        current_annos.sort(key=lambda x: x['software-name']['offsetStart'], reverse=True)
        
        # 遍历每个标注,插入<software>标签
        for anno in current_annos:
            software_name = anno['software-name']['rawForm']
            start = anno['software-name']['offsetStart']
            end = anno['software-name']['offsetEnd']
            current_pos = 0
            parent = p_elem
            
            # 检查段落初始文本节点
            initial_text = parent.text or ''
            if len(initial_text) > current_pos:
                if start < current_pos + len(initial_text):
                    # 拆分初始文本,插入软件标签
                    pre_text = initial_text[:start - current_pos]
                    software_text = initial_text[start - current_pos:end - current_pos]
                    post_text = initial_text[end - current_pos:]
                    
                    software_tag = etree.Element('software')
                    software_tag.text = software_text
                    parent.text = pre_text
                    software_tag.tail = post_text
                    parent.insert(0, software_tag)
                    continue
                current_pos += len(initial_text)
            
            # 遍历段落内的子节点(如<ref>),检查子节点的tail文本
            for i, child in enumerate(list(parent)):
                # 跳过子节点文本(示例中软件不在子节点内,如需处理可扩展)
                current_pos += len(child.text or '')
                tail_text = child.tail or ''
                tail_len = len(tail_text)
                
                if start < current_pos + tail_len:
                    # 拆分tail文本,插入软件标签
                    pre_tail = tail_text[:start - current_pos]
                    software_text = tail_text[start - current_pos:end - current_pos]
                    post_tail = tail_text[end - current_pos:]
                    
                    software_tag = etree.Element('software')
                    software_tag.text = software_text
                    software_tag.tail = post_tail
                    child.tail = pre_tail
                    parent.insert(i+1, software_tag)
                    break
                current_pos += tail_len
    
    # 返回格式化后的XML字符串
    return etree.tostring(root, encoding='unicode', pretty_print=True)

# 示例调用
if __name__ == '__main__':
    # 输入XML内容
    xml_input = '''<root>
<p> The reliability of the model structure was tested using the ENERGY commands of MODELLER <ref type="bibr" target="#b45">(Sali and Blundell, 1993)</ref>. The modelled structures were also validated using the program PROSA <ref type="bibr" target="#b54">(Wiederstein and Sippl, 2007)</ref>.</p>
</root>'''
    
    # 软件标注数据(实际可从JSON文件读取)
    software_annotations = [
        {
            "type": "software",
            "software-type": "software",
            "software-name": {
                "rawForm": "MODELLER",
                "normalizedForm": "MODELLER",
                "offsetStart": 79,
                "offsetEnd": 87,
                "boundingBoxes": [{"p": 1, "x": 495.722, "y": 320.344, "w": 53.9323, "h": 8.0517}]
            },
            "context": "The reliability of the model structure was tested using the ENERGY commands of MODELLER (Sali and Blundell, 1993)."
        },
        {
            "type": "software",
            "software-type": "software",
            "software-name": {
                "rawForm": "PROSA",
                "normalizedForm": "PROSA",
                "offsetStart": 194,
                "offsetEnd": 199,
                "boundingBoxes": [{"p": 1, "x": 495.722, "y": 320.344, "w": 53.9323, "h": 8.0517}]
            },
            "context": "The modelled structures were also validated using the program PROSA (Wiederstein and Sippl, 2007)."
        }
    ]
    
    # 处理并输出结果
    modified_xml = wrap_software_in_p(xml_input, software_annotations)
    print(modified_xml)

关键说明

  • 采用lxml库实现复杂节点操作,相比xml.etree更适合文本拆分与标签插入场景
  • 按偏移量降序处理标注,避免插入新节点后后续偏移量失效
  • 遍历段落的初始文本和子节点的tail文本,精准定位软件名称位置
  • 将原文本拆分为「前缀文本+软件名称+后缀文本」,创建<software>标签插入对应位置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:54:50