查找特定的 xml 标签并将标签内的文本替换为某个参数化值。多次出现需要更换。
示例文件内容:
<a>abc</a>
目前的尝试:
sed -i "s/\(<a>\).*\(<\/a>\)/\(<a>\)$param\(<\/a>\)/g" script.xml
期望的结果:如果 param=111 那么
<a>111</a>
答案1
我知道您需要一种sed
解决方案,但我通常推荐使用基于 XML 的工具(其中有很多),而不是sed
在处理除非常简单的工具之外的 XML 文档时。
假设这是我的 XML 文档 ( doc.xml
):
<?xml version="1.0"?>
<xml>
<c><a>abc</a></c>
<b>
<a>abc</a>
<a>abc</a>
</b>
<a parm="FPM">abc</a>
</xml>
我将使用以下 XML 样式表style.xsl
将文档转换为所需的格式。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name = "value" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a/text()[.='abc']">
<xsl:value-of select = "$value" />
</xsl:template>
</xsl:stylesheet>
我使用xsltproc
大多数主要 Linux 发行版上默认安装的工具来执行转换:
$ xsltproc --stringparam value "111" style.xsl doc.xml
<?xml version="1.0"?>
<xml>
<c><a>111</a></c>
<b>
<a>111</a>
<a>111</a>
</b>
<a parm="FPM">111</a>
</xml>
$
答案2
我编辑 XML 文件的首选工具是xmlstarlet
.假设这是我的 XML 文档(doc.xml
):
<?xml version="1.0"?>
<xml>
<c><a>abc</a></c>
<b>
<a>abc</a>
<a>abc</a>
</b>
<a parm="FPM">abc</a>
</xml>
这是xmlstarlet
命令:
param=111
xmlstarlet edit --ps --update '//a' --value "$param" doc.xml
输出
<?xml version="1.0"?>
<xml>
<c><a>111</a></c>
<b>
<a>111</a>
<a>111</a>
</b>
<a parm="FPM">111</a>
</xml>
答案3
- 这些
\(\)
在你的情况下是多余的。写吧sed -i "s/<a>.*<\/a>/<a>$param<\/a>/g" script.xml
- 如果您的字符串包含
/
,则使用不同的分隔符会更容易阅读:sed -i "s_<a>.*</a>_<a>$param</a>_g" script.xml
- 该选项表明一行上
g
可以有多个标签。<a>
这是一个问题: The.*
将匹配下一个</a>
、更多内容和最后一个<a>
,因此请防止包含其他标签:sed -i "s_<a>[^<]*</a>_<a>$param</a>_g" script.xml
<a>
请注意,如果标签内嵌套有其他标签或$param
包含特殊字符(例如"
或),则此操作将不起作用\
答案4
我会在 Perl 中执行此操作,而不是sed
因为 Perl 支持非贪婪匹配:
perl -i -pe "s|<a>.+?</a>|<a>$param</a>|g" file
这意味着“匹配最短的可能字符串”,因此这将找到 an和 an.+?
之间的最短字符串。<a>
</a>
然而,我必须强调,即使在稍微复杂的 XML 文档上,这也很可能会失败,您确实应该考虑使用专用的 XML 解析器。