我需要使用 bash 工具来解决几个问题
<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>
并将其删除。建议?
<CreateOfficeGroup>
<CreateOfficeName>John</CreateOfficeName>
<CreateOfficeCode>
</CreateOfficeCode>
</CreateOfficeGroup>
至:
<CreateOfficeGroup>
<CreateOfficeName>John</CreateOfficeName>
</CreateOfficeGroup>
<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>
您能以个人身份回答问题吗?非常感谢!
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())
sed '#n
1h;1!H
$ { x
:remtag
s#\(\n* *\)*<\([^>]*>\)\( *\n*\)*</\2##g
t remtag
p
}' YourFile
(GNU sed 上的 posix 版本所以
--posix
)
<tag1 prop="<tag2></tag2>"> ...
的内容也会删除 prop 内容以及 xml 允许的任何其他内容。您可以使用 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
) 只是删除连续的换行符。