Bash,删除空 XML 标签

问题描述 投票:0回答:3

我需要使用 bash 工具来解决几个问题

  1. 我想从文件中删除空的 xml 标签,例如:
 <CreateOfficeCode>
      <OperatorId>ve</OperatorId>
      <OfficeCode>1234</OfficeCode>
      <CountryCodeLength>0</CountryCodeLength>
      <AreaCodeLength>3</AreaCodeLength>
      <Attributes></Attributes>
      <ChargeArea></ChargeArea>
 </CreateOfficeCode>

成为:

 <CreateOfficeCode>
      <OperatorId>ve</OperatorId>
      <OfficeCode>1234</OfficeCode>
      <CountryCodeLength>0</CountryCodeLength>
      <AreaCodeLength>3</AreaCodeLength>
 </CreateOfficeCode>

为此我已经通过此命令完成了

sed -i '/><\//d' file

这并不那么严格,它更像是一个技巧,更合适的方法是找到

<pattern></pattern>
并将其删除。建议?

  1. 二、如何前往:
 <CreateOfficeGroup>
       <CreateOfficeName>John</CreateOfficeName>
       <CreateOfficeCode>
       </CreateOfficeCode>
 </CreateOfficeGroup>

至:

 <CreateOfficeGroup>
       <CreateOfficeName>John</CreateOfficeName>
 </CreateOfficeGroup>
  1. 整体而言?来自:
 <CreateOfficeGroup>
       <CreateOfficeName>John</CreateOfficeName>
       <CreateOfficeCode>
            <OperatorId>ve</OperatorId>
            <OfficeCode>1234</OfficeCode>
            <CountryCodeLength>0</CountryCodeLength>
            <AreaCodeLength>3</AreaCodeLength>
            <Attributes></Attributes>
            <ChargeArea></ChargeArea>
       </CreateOfficeCode>
       <CreateOfficeSize>
            <Chairs></Chairs>
            <Tables></Tables>
       </CreateOfficeSize>
 </CreateOfficeGroup>

至:

 <CreateOfficeGroup>
       <CreateOfficeName>John</CreateOfficeName>
       <CreateOfficeCode>
            <OperatorId>ve</OperatorId>
            <OfficeCode>1234</OfficeCode>
            <CountryCodeLength>0</CountryCodeLength>
            <AreaCodeLength>3</AreaCodeLength>
       </CreateOfficeCode>
 </CreateOfficeGroup>

您能以个人身份回答问题吗?非常感谢!

xml linux bash sed
3个回答
9
投票

XMLStarlet 是一个命令行 XML 处理器。使用它执行您想要的操作是一项单行操作(直到添加所需的递归行为),并且适用于描述相同输入的 XML 语法的所有变体:

简单版:

xmlstarlet ed \
  -d '//*[not(./*) and (not(./text()) or normalize-space(./text())="")]' \
  input.xml

精美版本:

strip_recursively() {
  local doc last_doc
  IFS= read -r -d '' doc 
  while :; do
    last_doc=$doc
    doc=$(xmlstarlet ed \
           -d '//*[not(./*) and (not(./text()) or normalize-space(./text())="")]' \
           /dev/stdin <<<"$last_doc")
    if [[ $doc = "$last_doc" ]]; then
      printf '%s\n' "$doc"
      return
    fi
  done
}
strip_recursively <input.xml
使用

/dev/stdin
而不是
-
(以平台可移植性为代价),以便在 XMLStarlet 版本之间实现更好的可移植性;调整口味。


对于仅安装较旧依赖项的系统,更有可能安装与 Python 捆绑在一起的 XML 解析器。

#!/usr/bin/env python

import xml.etree.ElementTree as etree
import sys

doc = etree.parse(sys.stdin)
def prune(parent):
    ever_changed = False
    while True:
        changed = False
        for el in parent.getchildren():
            if len(el.getchildren()) == 0:
                if ((el.text is None or el.text.strip() == '') and
                    (el.tail is None or el.tail.strip() == '')):
                    parent.remove(el)
                    changed = True
            else:
                changed = changed or prune(el)
        ever_changed = changed or ever_changed
        if changed is False:
            return ever_changed

prune(doc.getroot())
print etree.tostring(doc.getroot())

4
投票
sed '#n
1h;1!H
$ { x
:remtag
  s#\(\n* *\)*<\([^>]*>\)\( *\n*\)*</\2##g
  t remtag

  p
  }' YourFile

(GNU sed 上的 posix 版本所以

--posix

  • 递归地将空标签从下一级到上一级删除,直到不再出现空标签。
  • 不是 XML 解析器,因此类似
    <tag1 prop="<tag2></tag2>"> ...
    的内容也会删除 prop 内容以及 xml 允许的任何其他内容。

3
投票

您可以使用 sed 执行以下操作:

sed -i ':a;N;$!ba;s/<\([^>]*\)>[ \t\n]*<\/\1>//g;s/\([\n][\t\n ]*[\n]\)/\n/g;' yourfile.xml

开头的脚本 (

:l;N;$!bl
) 通过循环将所有行一起附加到模式空间(:a - 声明标签 a;N - 将下一行附加到模式空间;$!bl - 分支到 if last未到达线)

第一个替换的模式是像开始标签 (

<\([^>]*\)>
) - 可选空格 (
[ \t\n]*
) - 结束标签 (
<\/\1>
) 一样构建的。请注意标签名称模式周围的转义括号,其内容可以在表达式中稍后引用。这就是结束标签与开始标签的匹配方式。

最后,第二次替换 (

s/[\n][\n]*/\n/g
) 只是删除连续的换行符。

© www.soinside.com 2019 - 2024. All rights reserved.