сравнить два файла xml и обновить определенный ключ только с помощью xmlstarlet
Я пытаюсь сравнить два файла xml и обновить только определенный ключ в качестве нового файла. Проблема возникает, когда я экспортирую шаблон zabbix и пытаюсь импортировать в другую среду, статус должен быть оставлен как целевой. Предположим, у меня есть два файла xml,
source.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>
destination.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>
Итак, моей целью было бы создать новый файл и поставить ключ / значение «ОТКЛЮЧЕНО», как показано ниже.
final.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>
Я нашел один из наиболее близких способов добиться этого в сообщении. Обновление двух файлов xml с помощью xmlstarlet, но все же требуется небольшое прикосновение. Так что, кажется, лучше использовать xmlstarlet, так как мне нужно запускать эту малышку в Debian изначально.
Было бы здорово хотя бы подсказать, как это использовать таким образом.
Заранее спасибо,
1 ответ
Вот два способа решить эту проблему, оба предполагают , что
- элементы имеют уникальные
name
с - используется оболочка POSIX
Во-первых, преобразование XSLT 1.0, которое добавит элемент из одноименного файла . Это базовое преобразование идентичности , которое изменяет соответствующие 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 сложнее, так как существуют ограничения как на
xmlstarlet select
и операции: первый не копирует весь ввод, второй не принимает условные выражения (кроме выражений 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
Для каждого -less
trigger
в этой команде ищет одноименный элемент в
destination.xml
наличие непустого
status
элемент; при совпадении испускает
-s
(подузел) пункт для
xmlstarlet edit
для таргетинга на соответствующий узел в
source.xml
.
-o
выводит буквальный текст,
-n
новая строка,
-f
входной путь,
-b
завершает текущий контейнер (
-m
,
--if
,
--var
). Переменные
sq
а также
dq
помочь в цитировании
Выход:
xmlstarlet edit \
-s '//triggers/trigger[name="testtrig1"]' -t elem -n status -v 'DISABLED' \
source.xml
Беги как
xmlstarlet-sel-command-above | sh -s > final.xml
для выполнения вывода в виде сценария оболочки.