Манипулирование командной строкой XML (сценарий оболочки)

9

Как манипулировать XML из командной строки в сценарии оболочки?

Есть много команд для манипулирования табличными данными, замены переменных среды или замены текстовых фрагментов регулярным выражением, но я ничего не нашел для XML.

Мой сценарий сборки должен вставить тег с содержимым в основной тег документа xml, и я считаю излишним устанавливать для этого java, perl или python в ОС (мои сценарии выполняются в gitlab с образами docker, поэтому моя работа с инструментами, доступными в maven: изображение 3.5-jdk-8 было бы мечтой).

Я не хочу манипулировать XML с помощью sed, хотя в моем скрипте сборки это будет работать, потому что это зло .

Пример: у меня есть следующий XML:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>  
  <!-- a lot of other tags-->
</project>  

И я хочу вставить следующий блок:

<distributionManagement>
    <repository>
        <id>private-releases</id>
        <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
</distributionManagement>

внутри тега проекта (и не имеет значения, будет ли он в начале или в конце.

9ilsdx 9rvj 0lo
источник
опубликуйте
Таким образом, особые требования предъявляются к анализатору XML, который можно вызывать из командной строки, который не реализован ни на одном из основных языков сценариев, а является автономной утилитой C или C ++ (или другой скомпилированной)?
Кусалананда
@Kusalanda Я указал, что я запускаю скрипты в контейнерах докеров, поэтому для меня очень важно добавить как можно меньше к изображению докера.
9ilsdx 9rvj 0lo
Если у вас есть образ с maven и jdk, тогда Java звучит как лучший вариант для меня .... почему вы считаете Java в этом случае тяжелым?
Даниэль Приден
Вероятно, стоит задать этот вопрос о переполнении стека и пометить тегами maven- я подозреваю, что есть лучший способ сделать то, что вы пытаетесь сделать в самом Maven.
Даниэль Приден

Ответы:

10

XMLStarlet ( http://xmlstar.sourceforge.net/overview.php ) написан на C и использует libxml2и libxslt.

Учитывая документ XML

<?xml version="1.0"?>
<root>
  <tag>data</tag>
</root>

можно добавить подузел, rootиспользуя

xml ed -s '/root' -t elem -n 'newtag' -v 'newdata' file.xml

который производит

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>newdata</newtag>
</root>

Вставка многих вещей (используя оригинал file.xmlвверху):

xml ed -s '/root' -t elem -n 'newtag' \
       -s '/root/newtag' -t elem -n 'subtag' -v 'subdata' file.xml

Это производит

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>
    <subtag>subdata</subtag>
  </newtag>
</root>

Для примера в вопросе:

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -s '/x:project/distributionManagement' -t elem -n 'repository' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'id' \
         -v 'private-releases' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'url' \
         -v 'https://my.private.server.com/nexus/repository/maven-releases/' \
    file.xml

Результат:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

Вставка предварительно подготовленного XML-файла в местоположение в XML:

Предполагая, что исходный XML из вопроса находится в, file.xmlи дополнительные биты, которые должны идти в новом distributinManagementузле, находятся new.xml(но не сам тег узла), можно сделать следующее для вставки new.xmlв корневой узел:

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -v "$(<new.xml)" file.xml | xml unesc | xml fo

XMLStarlet автоматически избежать данных , которая нуждается в убегающих, такие как <и >символы. xml unescБит декодирует введенные данные (это фактически декодирует весь документ, который может или не может быть проблемой) и xml foпереформатирует полученный XML - документ.

Результат

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

Мне немного неловко делать это так, «но это работает».

См. Также этот связанный вопрос на StackOverflow: /programming/29298507/xmlstarlet-xinclude-xslt

Кусалананда
источник
Это выглядит интересно, хотя для вставки более одного тега синтаксис довольно длинный. Только то, что в Ubuntu он называется «xmlstarlet». Можно ли вставить содержимое другого файла в качестве тега, предполагая, что содержимое является допустимым XML?
9ilsdx 9rvj 0lo
@ 9ilsdx9rvj0lo Смотрите обновленный ответ.
Кусалананда
«на самом деле он удаляет весь документ, что может быть или не быть проблемой». Да, огромная проблема, все существующие & amp; были незашифрованы, в результате чего XML больше не действителен :(
ограбить
1

С этой целью я считаю излишним устанавливать java, perl или python в ОС (мои сценарии выполняются в gitlab с образами докеров, поэтому выполнять свою работу с помощью инструментов, доступных в maven: образ 3.5-jdk-8, было бы мечтой).

Возможно, это все еще излишне, но если вас интересует только размер контейнера, вы можете использовать очень легкий язык, такой как Lua или Guile.

из документов Lua:

Добавление Lua в приложение не увеличивает его. Tarball для Lua 5.3.4, который содержит исходный код и документацию, принимает сжатые файлы размером 297 тыс. И несжатые 1,1 млн. Исходный код содержит около 24000 строк C. В 64-битном Linux интерпретатор Lua, построенный со всеми стандартными библиотеками Lua, занимает 246 КБ, а библиотека Lua - 421 КБ.

Бруно Куконато
источник
Стоит подумать о простом добавлении LUA в контейнер maven, спасибо за подсказку.
9ilsdx 9rvj 0lo