xmlstarlet foreach节点更新值

xmlstarlet foreach node update value

我正在尝试使用 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 provider nodes 并将最终 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>

有没有办法在 providers 上执行 foreach 并将所有 my.corp 实例替换为 new.my.corp

一般来说,像这样使用xmlstarlet的-x选项:

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 指定的所有属性值替换为在 xmlstarlet 的 -x 参数中构造的值。

AFAIK xmlstarlet 不支持 RegEx,因此您必须使用 XPath-1.0 函数创建替换表达式,如 substring-after(...)substring(...) 等。


如果您需要 RegEx 来替换,则必须使用 XSLT-2.0 中的 XPath-2.0 函数。然后您可以使用如下所示的 XSLT-2.0 样式表来实现相同的目的,但使用 RegEx:

<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 处理器。两个参数都使用您的默认值进行了初始化。