Manipulação de linha de comando XML (shell script)

9

Como manipular XML da linha de comando no shell script?

Existem muitos comandos para manipular dados tabulares, substituir variáveis ​​de ambiente ou substituir fragmentos de texto por regex, mas não encontrei nada para XML.

Meu script de construção precisa inserir uma tag com conteúdo na tag principal do documento xml, e considero um exagero instalar java, perl ou python no SO para esse fim (meus scripts são feitos no gitlab com imagens do docker, fazendo isso meu trabalho com as ferramentas disponíveis no maven: a imagem 3.5-jdk-8 seria um sonho).

Eu não quero manipular XML com sed, embora no meu script de construção funcionasse, porque é ruim .

Exemplo: Eu tenho o seguinte 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>  

E eu quero inserir o seguinte bloco:

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

dentro da tag do projeto (e não importa se será no início ou no final).

9ilsdx 9rvj 0lo
fonte
postar sua xml entrada e saída esperada
RomanPerekhrest
Portanto, os requisitos específicos são para um analisador XML que pode ser chamado a partir da linha de comando que não é implementada em nenhuma das principais linguagens de script, mas em um utilitário independente C ou C ++ (ou outro compilado)?
Kusalananda
@ Kusalanda Eu especifiquei que estou executando scipts em contêineres do docker, por isso é mais importante adicionar o mínimo possível à imagem do docker.
precisa saber é o seguinte
Se você tem uma imagem com maven e jdk, o Java parece a melhor opção para mim ... por que você considera o Java pesado neste caso?
Daniel Pryden
Provavelmente vale a pena fazer esta pergunta no Stack Overflow e marcar com maven- suspeito que haja uma maneira melhor de fazer o que você está tentando fazer no próprio Maven.
Daniel Pryden

Respostas:

10

O XMLStarlet ( http://xmlstar.sourceforge.net/overview.php ) está escrito em C e usa libxml2e libxslt.

Dado o documento XML

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

um subnó rootpode ser inserido usando

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

que produz

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

Inserindo muitas coisas (usando o original file.xmlna parte superior aqui):

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

Isso produz

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

Para o exemplo na pergunta:

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

Resultado:

<?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>

Inserindo um arquivo XML preparado anteriormente em um local no XML:

Supondo que o XML original da pergunta esteja file.xmle que os bits adicionais que devem aparecer no novo distributinManagementnó estejam new.xml(mas não a própria tag do nó), é possível fazer o seguinte para inserir new.xmlno nó raiz:

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 vai escapar automaticamente os dados que precisa escapar, como <e >personagens. O xml unescbit remove os dados inseridos (na verdade, remove o documento inteiro, o que pode ou não ser um problema) e xml foreformata o documento XML resultante.

O resultado é

<?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>

Estou um pouco desconfortável em fazer dessa maneira ", mas funciona".

Consulte também esta pergunta relacionada no StackOverflow: /programming/29298507/xmlstarlet-xinclude-xslt

Kusalananda
fonte
Parece interessante, embora, para inserir mais de uma única tag, a sintaxe seja bastante longa. Só que no ubuntu é chamado 'xmlstarlet'. É possível inserir o conteúdo de outro arquivo como tag, assumindo que o conteúdo seja um xml válido?
precisa saber é o seguinte
@ 9ilsdx9rvj0lo Veja a resposta atualizada.
Kusalananda
"ele realmente tira o documento inteiro, o que pode ou não ser um problema". Sim enorme problema, todo o existente & amp; foram codificados, fazendo com que o XML não seja mais válido :(
rob
1

Acho um exagero instalar java, perl ou python no SO para esse fim (meus scripts são feitos no gitlab com imagens do docker, portanto, fazer meu trabalho com as ferramentas disponíveis no maven: imagem de 3,5-jdk-8 seria um sonho).

provavelmente ainda é um exagero, mas se você estiver preocupado apenas com o tamanho do contêiner, poderá usar uma linguagem muito leve, como Lua ou Guile.

dos documentos de Lua:

Adicionar Lua a um aplicativo não o inchará. O tarball para Lua 5.3.4, que contém código fonte e documentação, leva 297K compactados e 1,1M descompactados. A fonte contém cerca de 24000 linhas de C. No Linux de 64 bits, o interpretador Lua construído com todas as bibliotecas padrão Lua leva 246K e a biblioteca Lua leva 421K.

bruno cuconato
fonte
Vale a pena considerar simplesmente adicionar LUA ao contêiner de maven, obrigado pela dica.
9ilsdx 9rvj 0lo