我需要一些帮助,使用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>
您能否以个人身份回答问题?非常感谢你!
答案 0 :(得分:5)
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版本之间实现更好的可移植性;适应味道。
如果系统只安装了较旧的依赖项,则安装的XML解析器更可能与Python捆绑在一起。
#!/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())
答案 1 :(得分:4)
sed '#n
1h;1!H
$ { x
:remtag
s#\(\n* *\)*<\([^>]*>\)\( *\n*\)*</\2##g
t remtag
p
}' YourFile
(在GNU sed上的posix版本--posix
)
<tag1 prop="<tag2></tag2>"> ...
这样的东西也会删除道具内容以及xml允许的任何其他内容。答案 2 :(得分:2)
您可以使用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 - branch到达最后一行的if)
第一次替换的模式就像开始标记(<\([^>]*\)>
) - 可选的空格([ \t\n]*
) - 结束标记(<\/\1>
)一样。请注意标记名称模式周围的转义parens,其内容在表达式中可以称为\ 1。这就是结束标记与开始标记的匹配方式。
最后,第二次替换(s/[\n][\n]*/\n/g
)只是删除了连续的换行符。