xml - xmlstarlet foreach 节点更新值
问题描述
我正在尝试使用 xmlstarlet 更新具有相同模式的所有节点。给定以下 xml
<root>
<application>
<provider name="alpha" value="my.corp.lion" />
<provider name="beta" value="my.corp.tiger" />
<provider name="gamma" value="my.corp.monkey" />
</application>
</root>
我目前可以按如下方式更新每个节点
oldCorp="my.corp"
newCorp="new.my.corp"
myNode="/root/application/provider[@name='alpha']/@value"
oldValue=$(xml sel -t -v ${myNode} MyXml.xml)
newValue=${oldValue//$oldCorp/$newCorp}
xml ed --inplace -u ${myNode} -v "${newValue}" MyXml.xml
# results in provider.alpha being new.my.corp.lion
但是,我希望能够做的是 foreach ALL 提供程序节点并将最终的 xml 结果更新为
<root>
<application>
<provider name="alpha" value="new.my.corp.lion" />
<provider name="beta" value="new.my.corp.tiger" />
<provider name="gamma" value="new.my.corp.monkey" />
</application>
</root>
有没有办法对 进行 foreachproviders
并将所有my.corp
实例替换为new.my.corp
?
解决方案
一般来说,-x
像这样使用 xmlstarlet 的选项:
xmlstarlet ed --inplace -u "/root/application/provider/@value" -x "concat('new.my.corp',substring-after(.,'my.corp'))" input.xml
在您的特殊情况下,将代码更改为
oldCorp="my.corp"
newCorp="new.my.corp"
myNode="/root/application/provider/@value"
xml ed --inplace -u "${myNode}" -x "concat('${newCorp}',substring-after(.,'${oldCorp}'))" MyXml.xml
输出如所愿:
<?xml version="1.0"?>
<root>
<application>
<provider name="alpha" value="new.my.corp.lion"/>
<provider name="beta" value="new.my.corp.tiger"/>
<provider name="gamma" value="new.my.corp.monkey"/>
</application>
</root>
此代码将myNode
XPath指定的所有属性值替换-x
为 xmlstarlet 参数中构造的值。
AFAIK xmlstarlet 不支持正则表达式,因此您必须使用 XPath-1.0 函数(如 等)创建替换substring-after(...)
表达式substring(...)
。
如果您需要 RegEx 来替换,您必须使用 XSLT-2.0 中的 XPath-2.0 函数。然后,您可以使用如下的 XSLT-2.0 样式表来实现相同的目的,但使用 RegEx'es:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:param name="oldCorp" select="'my\.corp'" />
<xsl:param name="newCorp" select="'new.my.corp'" />
<!-- Identity template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="provider">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:attribute name="value">
<xsl:value-of select="replace(@value,$oldCorp,$newCorp)" />
</xsl:attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您可以将参数作为字符串传递给 XSLT-2.0 处理器。这两个参数都使用您的默认值进行初始化。
推荐阅读
- linux - bash elif 梯子的奇怪结果
- django - 根据页面设置在模板中设置 LANGUAGE_CODE
- mysql - 如何在 AWS RDS 中将时区设置为 EST
- docker - 如何访问 docker-compose.yml 中的其他容器 ID?
- jquery - 如何水平拖动 Grid Stack 块?
- javascript - 使用自定义样式打印引导网格布局
- css - CSS 伪 :dir(); :host-context() 和基于方向性的样式
- https - 如何找到我的服务器的公钥信息以在 OkHttp 中进行证书固定?
- python - 启动 spyder 时出现此错误
- python - AnalysisException:在根据前几行计算列值时,窗口函数中不支持表达式