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

如何使用Python为带嵌套标签的XML文本添加标记?

解决XML嵌套标签下关键词添加标记的问题

你遇到的问题本质是XML元素的文本并非只存在于text属性中——当有嵌套子元素时,子元素后面的文本会被存在子元素的tail属性里,原代码只处理了父元素的text(也就是第一个子元素之前的文本),自然找不到后面的关键词。

而且直接用字符串拼接<key>标签的方式不可取,这会破坏XML的结构,应该用ElementTree的API来创建和插入元素,保证XML的合法性。

解决思路

  • 递归遍历XML的所有元素,处理元素自身的text和所有子元素的tail
  • 对于每个文本片段,拆分出关键词,将关键词替换为<key>元素,把拆分后的文本和新元素重新插入到XML树中

修正后的代码

import xml.etree.ElementTree as ET

def wrap_keywords(element, keywords):
    # 处理当前元素的text内容
    if element.text:
        parts = []
        current_pos = 0
        text = element.text
        for keyword in keywords:
            idx = text.find(keyword, current_pos)
            while idx != -1:
                # 添加关键词之前的普通文本
                if idx > current_pos:
                    parts.append(text[current_pos:idx])
                # 添加关键词对应的<key>元素
                key_elem = ET.Element("key")
                key_elem.text = keyword
                parts.append(key_elem)
                current_pos = idx + len(keyword)
                idx = text.find(keyword, current_pos)
        # 添加剩余的普通文本
        if current_pos < len(text):
            parts.append(text[current_pos:])
        
        # 清空原text,重新构建子节点
        element.text = None
        for part in parts:
            if isinstance(part, str):
                # 文本节点直接作为前一个节点的tail,或元素的text
                last_child = list(element)[-1] if list(element) else None
                if last_child is not None:
                    last_child.tail = (last_child.tail or "") + part
                else:
                    element.text = part
            else:
                element.append(part)
    
    # 递归处理子元素,并处理子元素的tail
    for child in list(element):
        wrap_keywords(child, keywords)
        # 处理子元素的tail内容
        if child.tail:
            parts = []
            current_pos = 0
            tail_text = child.tail
            for keyword in keywords:
                idx = tail_text.find(keyword, current_pos)
                while idx != -1:
                    if idx > current_pos:
                        parts.append(tail_text[current_pos:idx])
                    key_elem = ET.Element("key")
                    key_elem.text = keyword
                    parts.append(key_elem)
                    current_pos = idx + len(keyword)
                    idx = tail_text.find(keyword, current_pos)
            if current_pos < len(tail_text):
                parts.append(tail_text[current_pos:])
            
            # 清空原tail,将拆分后的内容插入到当前子元素之后
            child.tail = None
            parent = element
            child_index = list(parent).index(child)
            for i, part in enumerate(parts):
                if isinstance(part, str):
                    # 文本作为前一个节点的tail
                    prev_node = list(parent)[child_index + i] if (child_index + i) < len(list(parent)) else child
                    prev_node.tail = (prev_node.tail or "") + part
                else:
                    parent.insert(child_index + i + 1, part)

# 测试代码
doc = '''<root><par>An <fr>example</fr> text with key words one and two</par></root>'''
profs = ['one', 'two']

root = ET.fromstring(doc)
wrap_keywords(root, profs)

# 输出处理后的XML
ET.indent(root)
print(ET.tostring(root, encoding='unicode'))

代码说明

  • wrap_keywords函数递归处理每个元素:
    1. 先处理元素自身的text,把包含关键词的文本拆分成普通文本和<key>元素,替换原有的text
    2. 递归处理子元素,确保嵌套标签内部的文本也能被处理(如果需要的话)
    3. 处理子元素的tail——这就是原代码遗漏的部分,子元素后面的文本都在这里,同样拆分后插入到子元素之后

运行后会输出结构合法的XML,其中one和two被正确包裹在<key>标签内:

<root>
  <par>An <fr>example</fr> text with key words <key>one</key> and <key>two</key></par>
</root>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:05:02