-1

我正在尝试比较两个 xml 文件并仅将某个键更新为新文件。当我导出 zabbix 模板并尝试在另一个环境中导入时,会出现此问题,状态应保留为目标之一。假设我有两个 xml 文件,

源代码.xml

<zabbix_export>
    <version>5.0</version>
    <groups>
        <group>
            <name>zabbix</name>
        </group>
    </groups>
    <templates>
        <template>
            <template>testtemp</template>
            <name>testtemp</name>
            <groups>
                <group>
                    <name>zabbix</name>
                </group>
            </groups>
            <items>
                <item>
                    <name>test1</name>
                    <key>kernel.maxproc</key>
                    <triggers>
                        <trigger>
                            <expression>{last()}=0</expression>
                            <name>testtrig1</name>
                        </trigger>
                        <trigger>
                            <expression>{last()}=100</expression>
                            <name>testtrig2</name>
                        </trigger>
                    </triggers>
                </item>
            </items>
        </template>
    </templates>
</zabbix_export>

目的地.xml

    <version>5.0</version>
    <groups>
        <group>
            <name> zabbix </name>
        </group>
    </groups>
    <templates>
        <template>
            <template>testtemp</template>
            <name>testtemp</name>
            <groups>
                <group>
                    <name>zabbix</name>
                </group>
            </groups>
            <items>
                <item>
                    <name>test1</name>
                    <key>kernel.maxproc</key>
                    <triggers>
                        <trigger>
                            <expression>{last()}=0</expression>
                            <name>testtrig1</name>
                            <status>DISABLED</status>
                        </trigger>
                    </triggers>
                </item>
            </items>
        </template>
    </templates>
</zabbix_export> 

所以我的目标是创建一个新文件并将键/值“禁用”如下所示。

最终的.xml

<zabbix_export>
    <version>5.0</version>
    <groups>
        <group>
            <name>zabbix</name>
        </group>
    </groups>
    <templates>
        <template>
            <template>testtemp</template>
            <name>testtemp</name>
            <groups>
                <group>
                    <name>zabbix</name>
                </group>
            </groups>
            <items>
                <item>
                    <name>test1</name>
                    <key>kernel.maxproc</key>
                    <triggers>
                        <trigger>
                            <expression>{last()}=0</expression>
                            <name>testtrig1</name>
                            <status>DISABLED</status>
                        </trigger>
                        <trigger>
                            <expression>{last()}=100</expression>
                            <name>testtrig2</name>
                        </trigger>
                    </triggers>
                </item>
            </items>
        </template>
    </templates>
</zabbix_export>

我在使用 xmlstarlet 更新两个 xml 文件的帖子中找到了实现此行为的最接近的方法之一,但仍然需要一点点接触。所以使用 'xmlstarlet' 似乎更好,因为我需要在 Debian 本地运行这个宝贝。

至少提供一个线索如何以这种方式使用它会很棒。

提前致谢,

4

1 回答 1

0

这里有两种解决方法,都假设

  • trigger元素具有唯一name
  • 使用 POSIX shell

首先,一个 XSLT 1.0 转换将添加status来自同名triggerin的元素destination.xml。这是一个基本的 恒等变换 ,它修改了适当trigger的 s。如果您想限制某些状态值,您可以添加,例如,添加 and $dstat = "DISABLED"xsl:if test子句中。

<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:strip-space elements="*"/>
  <xsl:param name="ddoc" select="'destination.xml'"/>
  <xsl:variable name="dtt" select="document($ddoc)//triggers/trigger"/>
  
  <xsl:template match="@*|node()" name="identity">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="triggers/trigger[not(status)]">
    <xsl:variable name="dstat" 
        select="$dtt[name = current()/name]/status"/>
    <xsl:copy>
      <xsl:apply-templates/>
      <xsl:if test="string($dstat)">
        <xsl:copy-of select="$dstat"/>
      </xsl:if>
    </xsl:copy>
  </xsl:template>

</xsl:transform>

运行方式

xsltproc --stringparam ddoc destination.xml delta.xsl source.xml > final.xml

或者

xmlstarlet tr delta.xsl -s ddoc=destination.xml source.xml > final.xml

速记中做同样的事情比较棘手,因为xmlstarlet select和操作都有限制xmlstarlet edit :前者不复制整个输入,后者不接受条件(XPath 表达式除外)。但是,可以将 select其用作代码生成器来生成edit命令。(在 . 之前列出生成的 XSLT 1.0 代码添加-C选项-t。)

xmlstarlet sel -t \
  --var sq -o "'" -b \
  --var dq -o '"' -b \
  --var ddoc="'destination.xml'" \
  --var dtt='document($ddoc)//triggers/trigger' \
  -o 'xmlstarlet edit \' -n \
  -m '//triggers/trigger[not(status)]' \
    --var dstat='$dtt[name = current()/name]/status' \
    --if 'string($dstat)' \
      -o ' -s ' -v 'concat($sq,"//triggers/trigger[name=",$dq,current()/name,$dq,"]",$sq)' \
      -o ' -t elem -n status -v ' -v 'concat($sq,$dstat,$sq)' -o ' \' -n \
    -b \
  -b -f -n source.xml

对于此命令中的每个status-less trigger,查找具有非空元素source.xml的同名 元素;on match 发出一个(subnode) 子句, 用于定位. 输出文字文本、换行符、输入路径名、结束当前容器 ( , , )。变量和辅助引用destination.xmlstatus-sxmlstarlet editsource.xml-o-n-f-b-m--if--varsqdq

输出:

xmlstarlet edit \
 -s '//triggers/trigger[name="testtrig1"]' -t elem -n status -v 'DISABLED' \
source.xml

运行方式

xmlstarlet-sel-command-above | sh -s > final.xml

将输出作为 shell 脚本执行。

于 2021-12-24T15:01:36.700 回答