Manipulation de la ligne de commande XML (script shell)

9

Comment manipuler XML à partir de la ligne de commande dans un script shell?

Il existe de nombreuses commandes pour manipuler les données tabulaires, remplacer la variable d'environnement ou remplacer les fragments de texte par regex, mais je n'ai rien trouvé pour XML.

Mon script de construction doit insérer une balise avec du contenu dans la balise principale du document xml, et je trouve cela exagéré d'installer java, perl ou python dans le système d'exploitation à cet effet (mes scripts sont effectués dans gitlab avec des images de docker, ce faisant mon travail avec les outils disponibles dans maven: l'image 3,5-jdk-8 serait un rêve).

Je ne veux pas manipuler XML avec sed, bien que dans mon script de construction cela fonctionnerait, car c'est mal .

Exemple: j'ai le xml suivant:

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

Et je veux insérer le bloc suivant:

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

à l'intérieur de la balise de projet (et cela n'a pas vraiment d'importance si ce sera au début ou à la fin.

9ilsdx 9rvj 0lo
la source
publier votre entrée xml et sortie attendue
RomanPerekhrest
Donc, les exigences spécifiques sont pour un analyseur XML qui peut être appelé à partir de la ligne de commande qui n'est implémentée dans aucun des principaux langages de script, mais un utilitaire autonome C ou C ++ (ou autre compilé)?
Kusalananda
@Kusalanda J'ai spécifié que j'exécute des scipts dans des conteneurs Docker, il est donc très important pour moi d'ajouter le moins possible à l'image Docker.
9ilsdx 9rvj 0lo
Si vous avez une image avec maven et un jdk, Java semble être la meilleure option pour moi .... pourquoi considérez-vous Java lourd dans ce cas?
Daniel Pryden
Cela vaut probablement la peine de poser cette question sur Stack Overflow et le balisage avec maven- je pense qu'il y a une meilleure façon de faire ce que vous essayez de faire au sein de Maven lui-même.
Daniel Pryden

Réponses:

10

XMLStarlet ( http://xmlstar.sourceforge.net/overview.php ) est écrit en C et utilise libxml2et libxslt.

Étant donné le document XML

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

un sous-noeud à rootpeut être inséré à l'aide

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

qui produit

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

Insérer beaucoup de choses (en utilisant l'original file.xmlen haut ici):

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

Cela produit

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

Pour l'exemple de la question:

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

Résultat:

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

Insertion d'un fichier XML préalablement préparé à un emplacement dans le XML:

En supposant que le XML d'origine de la question est dans file.xmlet que les bits supplémentaires qui devraient aller dans le nouveau distributinManagementnœud sont dedans new.xml(mais pas la balise de nœud elle-même), on pourrait faire ce qui suit pour insérer new.xmldans le nœud racine:

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 échappera automatiquement les données à échapper, telles que les caractères <et >. Le xml unescbit échappe les données insérées (il échappe en fait tout le document, ce qui peut ou non être un problème), et xml foreformate le document XML résultant.

Le résultat est

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

Je suis un peu mal à l'aise de le faire de cette façon, "mais cela fonctionne".

Voir également cette question connexe sur StackOverflow: /programming/29298507/xmlstarlet-xinclude-xslt

Kusalananda
la source
Cela semble intéressant, bien que pour insérer plus d'une seule balise, la syntaxe soit assez longue. Seulement, dans ubuntu, il est nommé 'xmlstarlet'. Est-il possible d'insérer le contenu d'un autre fichier en tant que balise, en supposant que le contenu est un xml valide?
9ilsdx 9rvj 0lo
@ 9ilsdx9rvj0lo Voir la réponse mise à jour.
Kusalananda
"il échappe en fait à tout le document, ce qui peut ou non être un problème". Yep problème énorme, tous les & amp; existants ont été non codés, ce qui a rendu XML non valide :(
vol
1

Je trouve exagéré d'installer java, perl ou python dans le système d'exploitation à cet effet (mes scripts sont effectués dans gitlab avec des images de docker, donc faire mon travail avec les outils disponibles dans maven: l'image 3,5-jdk-8 serait un rêve).

c'est probablement encore exagéré, mais si vous ne vous souciez que de la taille du conteneur, vous pouvez utiliser un langage très léger tel que Lua ou Guile.

des documents Lua:

L'ajout de Lua à une application ne la gonfle pas. L'archive tar pour Lua 5.3.4, qui contient le code source et la documentation, prend 297 Ko compressés et 1,1 Mo non compressés. La source contient environ 24 000 lignes de C. Sous Linux 64 bits, l'interpréteur Lua construit avec toutes les bibliothèques Lua standard prend 246 Ko et la bibliothèque Lua 421 Ko.

bruno cuconato
la source
Cela vaut la peine d'envisager d'ajouter simplement LUA au conteneur maven, merci pour l'astuce.
9ilsdx 9rvj 0lo