Xmlstarlet выбирает узлы и добавляет подузлы

Я пытаюсь автоматизировать добавление новых подузлов в nexus-core-feature-3.16.1-02.xml, потому что мы используем некоторые плагины для работы, которые не поставляются с «коробочным» решением. Суть в том, что при выпуске новой версии nexus-контейнера у меня есть bash-скрипт, который запускает новую версию тестового контейнера и копирует новый XML-файл по умолчанию в нужную папку. Следующим шагом будет редактирование этого файла и добавление некоторых новых функций, чтобы плагин работал. Когда это сделано, старый контейнер останавливается, новый xml-заменяет старый, и я запускаю док-контейнер с сопоставленными данными nexus и default-xml. Для корректной работы этого плагина мне нужно внести некоторые изменения в файл default-xml. И я хочу использовать для этого xmlstarlet. Добавьте это в раздел «nexus-core-feature»:

<feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
  </feature>

И это до конца файла xml-файла

<feature name="nexus-repository-apt" description="net.staticsnow:nexus-repository-apt" version="1.0.10">
     <details>net.staticsnow:nexus-repository-apt</details>
     <bundle>mvn:net.staticsnow/nexus-repository-apt/1.0.10</bundle>
     <bundle>mvn:org.apache.commons/commons-compress/1.18</bundle>
     <bundle>mvn:org.tukaani/xz/1.8</bundle>
</feature>
</features>

Итак, я какое-то время гуглил и ТАК, но я все еще застрял. Например, в этом случае: Как вставить новый элемент в другой с xmlstarlet?

Кажется довольно простым сделать что-то подобное, и я попробовал это:

xmlstarlet ed -s /features/feature/feature -t elem -n featureTMP -v "nexus-apt-repositroy" \
    -i //featureTMP -t attr -n "version" -v "1.0.9" \
    -i //featureTMP P -t attr -n "prerequisite" -v "false" \
    -i //featureTMP -t attr -n "dependency" -v "false" \
    -r //featureTMP -v feature nexus-core-feature-3.16.1-02-features.xml

Я подозреваю, что моя ошибка была (и есть) в пути к узлам.

Следующим шагом было изучение узлов

xmlstarlet sel -t -c "/" nexus-core-feature-3.16.1-02-features.xml

На выходе был весь xml-файл, и вроде все в порядке

<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="nexus-core-feature">
    <feature name="nexus-core-feature" description="org.sonatype.nexus.assemblies:nexus-core-feature" version="3.16.1.02">
        <details>org.sonatype.nexus.assemblies:nexus-core-feature</details>
        <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-audit-plugin</feature>
        <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-blobstore-tasks</feature>
        <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-ssl-plugin</feature>
        <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-coreui-plugin</feature>
        <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-repository-httpbridge</feature>
...

Но когда я пытаюсь попасть в узел, результат всегда пустой:

xmlstarlet sel -t -c "/features" nexus-core-feature-3.16.1-02-features.xml

С селектором атрибутов он по-прежнему пуст:

xmlstarlet sel -t -c "/features/feature[@name="nexus-core-feature"]" nexus-core-feature-3.16.1-02-features.xml

Пробовал проверить это в тестере XPath-online, внутри тестера все в порядке.

Далее я использую более простой пример в этой статье: https://unix.stackexchange.com/questions/386965/insert-custom-xml-tag-into-a-xml-file-in-a-bash-script

и попытался просмотреть файл примера, который был в arctilce, и, похоже, все в порядке.

xmlstarlet sel -t -c "/server-groups" file.xml

выход:

<server-groups>
  <server-group name="main-server-group" profile="full">
    <jvm name="default">
      <heap size="64m" max-size="512m"/>
      <jvm-options>
        <option value="somevalue"/>
      </jvm-options>
    </jvm>
    <socket-binding-group ref="full-sockets"/>
  </server-group>
</server-groups>

Следующий шаг

xmlstarlet sel -t -c "/server-groups/server-group/jvm" file.xml

выход:

<jvm name="default">
      <heap size="64m" max-size="512m"/>
      <jvm-options>
        <option value="somevalue"/>
      </jvm-options>
    </jvm>

И это меня очень смущает... Почему тот же подход не работает с файлом nexus-xml? Более сложная\странная структура? Буду рад любому совету


person Афанасьев Дмитрий    schedule 22.04.2019    source источник


Ответы (1)


Почему тот же подход не работает с файлом nexus-xml?

Это потому, что ваш XML-файл nexus находится в пространстве имен по умолчанию (http://karaf.apache.org/xmlns/features/v1.4.0).

Если вы используете xmlstarlet версии 1.0.5 или более поздней, вы можете использовать _: в своем XPath для соответствия любому пространству имен. В противном случае вам придется привязать пространство имен к префиксу с -N. Подробнее см. здесь.

Вот обновленный пример вашей первой попытки:

xmlstarlet ed -s /_:features/_:feature -t elem -n featureTMP -v "nexus-repository-apt" \
    -i //featureTMP -t attr -n "version" -v "1.0.9" \
    -i //featureTMP -t attr -n "prerequisite" -v "false" \
    -i //featureTMP -t attr -n "dependency" -v "false" \
    -r //featureTMP -v feature nexus-core-feature-3.16.1-02-features.xml

Вот альтернативный подход использования -N...

xmlstarlet ed -N f="http://karaf.apache.org/xmlns/features/v1.4.0" -s /f:features/f:feature -t elem -n featureTMP -v "nexus-repository-apt" \
    -i //featureTMP -t attr -n "version" -v "1.0.9" \
    -i //featureTMP -t attr -n "prerequisite" -v "false" \
    -i //featureTMP -t attr -n "dependency" -v "false" \
    -r //featureTMP -v feature nexus-core-feature-3.16.1-02-features.xml    

Оба они производят следующий вывод:

<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="nexus-core-feature">
  <feature name="nexus-core-feature" description="org.sonatype.nexus.assemblies:nexus-core-feature" version="3.16.1.02">
    <details>org.sonatype.nexus.assemblies:nexus-core-feature</details>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-audit-plugin</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-blobstore-tasks</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-ssl-plugin</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-coreui-plugin</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-repository-httpbridge</feature>
    <feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
  </feature>
</features>

Добавить второй feature можно таким же образом, но вы также можете упростить все это, используя XSLT в xmlstarlet с команда tr. (В любом случае, на мой взгляд, это проще.)

XSLT (test.xsl)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:f="http://karaf.apache.org/xmlns/features/v1.4.0"
  xmlns="http://karaf.apache.org/xmlns/features/v1.4.0"
  exclude-result-prefixes="f">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="f:features">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <feature name="nexus-repository-apt" description="net.staticsnow:nexus-repository-apt" version="1.0.10">
        <details>net.staticsnow:nexus-repository-apt</details>
        <bundle>mvn:net.staticsnow/nexus-repository-apt/1.0.10</bundle>
        <bundle>mvn:org.apache.commons/commons-compress/1.18</bundle>
        <bundle>mvn:org.tukaani/xz/1.8</bundle>
      </feature>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="f:feature[@name='nexus-core-feature']">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

команда xmlstarlet

xmlstarlet tr test.xsl nexus-core-feature-3.16.1-02-features.xml

Вывод

<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="nexus-core-feature">
  <feature name="nexus-core-feature" description="org.sonatype.nexus.assemblies:nexus-core-feature" version="3.16.1.02">
    <details>org.sonatype.nexus.assemblies:nexus-core-feature</details>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-audit-plugin</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-blobstore-tasks</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-ssl-plugin</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-coreui-plugin</feature>
    <feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-repository-httpbridge</feature>
    <feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
  </feature>
  <feature name="nexus-repository-apt" description="net.staticsnow:nexus-repository-apt" version="1.0.10">
    <details>net.staticsnow:nexus-repository-apt</details>
    <bundle>mvn:net.staticsnow/nexus-repository-apt/1.0.10</bundle>
    <bundle>mvn:org.apache.commons/commons-compress/1.18</bundle>
    <bundle>mvn:org.tukaani/xz/1.8</bundle>
  </feature>
</features>
person Daniel Haley    schedule 22.04.2019
comment
Спасибо за отличный ответ Даниил! Кажется, это рабочее решение для меня, но все же нужно немного отредактировать для моего случая :) - person Афанасьев Дмитрий; 23.04.2019
comment
@АфанасьевДмитрий - Рад, что смог помочь! - person Daniel Haley; 23.04.2019