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? Более сложная\странная структура? Буду рад любому совету

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
989
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Why the same approach doesn't work with nexus-xml file?

Это потому, что ваш 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>

Спасибо за отличный ответ Даниил! Кажется, это рабочее решение для меня, но все же нужно немного отредактировать для моего случая :)

Афанасьев Дмитрий 23.04.2019 07:47

@АфанасьевДмитрий - Рад, что смог помочь!

Daniel Haley 23.04.2019 07:50

Другие вопросы по теме