我有这样的 XML:
<string name="foo-bar">"bar-bar -bar"</string>
<string name="asdf_qwe-rty" translatable="false">"Lorem ipsum"</string>
现在,该name
属性不能包含-
字符,所以我想将其替换为_
.
<string name="foo_bar">"bar-bar -bar"</string>
<string name="asdf_qwe_rty" translatable="false">"Lorem ipsum"</string>
我怎样才能做到这一点,最好是使用sed
?
答案1
假设 XML 文档格式良好,您可以使用以下方式替换所有节点属性中xmlstarlet
出现的所有字符:-
name
string
_
$ xmlstarlet ed -u '//string/@name' -x 'translate(.,"-","_")' file.xml
<?xml version="1.0"?>
<root>
<string name="foo_bar">"bar-bar -bar"</string>
<string name="asdf_qwe_rty" translatable="false">"Lorem ipsum"</string>
<string name="_test1_">name="-test1-"</string>
<!-- <string name="-test2-">name="-test2-"</string> -->
</root>
(我在此处添加了一个包装root
节点以使文档格式良好,并添加了一些额外的情况以表明我们不会影响节点值或注释内容)。
该xmlstarlet
表达式将使用 XPath 表达式 查找所有相关属性//string/@node
,并将每个属性的简单转换-
应用于_
每个属性的值。输出被写入标准输出。
答案2
任何基于 sed 的解决方案(或任何其他不进行正确 XML 解析的解决方案)在一定比例的边缘情况下都会出错。例如@Pitel的解决方案:
(a) 替换看起来像名称属性的内容,即使它们位于注释或文本中而不是位于开始标记中
firstname
(b) 还更改名为或的属性的内容lastname
(c) 如果等号周围有空格,则无法发现该属性。
因此,它可能足以满足一次性的临时使用,但不要将其放入生产工作流程中。如果您需要生产质量的东西,请使用 XSLT 转换。这并不难:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="@name">
<xsl:attribute name="name" select="translate(., '-', '_')"/>
</xsl:template>
</xsl:transform>
答案3
sed -r ':a; s/(name="[^-"]*)-/\1_/; ta'