如何用sed/awk删除XML中跨多行的嵌套同名标签?
处理XML中嵌套同名标签的解决方案
处理带有嵌套结构的XML时,sed这类面向行的工具容易因标签跨多行、嵌套逻辑复杂踩坑,以下是实用的解决方法:
一、AWK 解决方案(精准处理嵌套同名标签)
这个脚本通过跟踪标签层级,自动跳过内层的同名嵌套标签,仅保留最外层标签及内容:
BEGIN { FS = "<|>" stack_ptr = 0 } { while (match($0, /<\/?[^>]+>/, tags)) { tag = tags[0] sub(/<\/?[^>]+>/, "", $0) if (tag ~ /^<[^/]+>$/) { tag_name = substr(tag, 2, length(tag)-2) if (stack_ptr > 0 && stack[stack_ptr] == tag_name) { skip = 1 skip_tag = tag_name } else { print tag stack_ptr++ stack[stack_ptr] = tag_name } } else if (tag ~ /^<\/[^>]+>$/) { tag_name = substr(tag, 3, length(tag)-3) if (skip && skip_tag == tag_name) { skip = 0 } else { print tag stack_ptr-- } } if ($0 != "") { print $0 $0 = "" } } if ($0 != "") print $0 }
使用命令:
awk -f remove_nested_tags.awk your_file.xml > output.xml
二、SED 相关问题说明
- 跨多行匹配问题:sed默认按行处理,需用
N命令合并多行到模式空间,但对于嵌套XML,这种方式逻辑极易出错,不推荐用于复杂嵌套场景。 - 闭合标签的/转义:在sed的
s///替换语法中,若用/作为分隔符,闭合标签里的/需转义为\/。例如匹配</Id>,需写成\<\/Id\>(基础正则);若启用扩展正则(加-E参数),标签内的/无需转义,直接写</Id>即可。
三、XML单行化处理方案
若想将XML转为单行方便后续处理,可通过以下命令清理换行并拆分标签:
# 清理缩进空格后转为单行,再拆分标签到单独行 sed 's/^[[:space:]]*//; s/[[:space:]]*$//' your_file.xml | tr -d '\n' | sed 's/></>\n</g' > clean_single_line.xml
但单行化后,处理嵌套同名标签仍建议用awk,sed难以覆盖所有嵌套逻辑。
四、专业XML工具方案(最可靠)
优先推荐用xmlstarlet这类结构化XML工具,直接基于XML层级处理,精准度更高:
- 删除所有内层
<Id>标签:
xmlstarlet ed -d '//Id//Id' your_file.xml > output.xml
- 删除所有内层
<Dt>标签:
xmlstarlet ed -d '//Dt//Dt' your_file.xml > output.xml
系统未安装时,可通过包管理器安装(如apt install xmlstarlet或brew install xmlstarlet)。
内容的提问来源于stack exchange,提问作者Baldie47
相关产品推荐
相关产品推荐

