Manipolazione della riga di comando XML (shell script)


9

Come manipolare XML dalla riga di comando nello script della shell?

Esistono molti comandi per manipolare i dati tabulari, sostituire la variabile d'ambiente o sostituire i frammenti di testo con regex, ma non ho trovato nulla per XML.

Il mio script di compilazione deve inserire un tag con contenuto all'interno del tag principale del documento XML, e lo trovo eccessivo per installare java, perl o python nel sistema operativo a tale scopo (i miei script sono fatti in gitlab con immagini docker, quindi il mio lavoro con gli strumenti disponibili in Maven: l'immagine 3.5-jdk-8 sarebbe un sogno).

Non voglio manipolare XML con sed, anche se nel mio script build funzionerebbe, perché è malvagio .

Esempio: ho il seguente 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 voglio inserire il seguente blocco:

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

all'interno del tag del progetto (e non ha importanza se sarà all'inizio o alla fine.


pubblica il tuo input xml e output previsto
— RomanPerekhrest

Quindi i requisiti specifici sono per un parser XML che può essere invocato dalla riga di comando che non è implementato in nessuno dei principali linguaggi di scripting, ma un'utilità indipendente C o C ++ (o altra compilata)?
— Kusalananda

@Kusalanda Ho specificato che sto eseguendo script all'interno dei contenitori della finestra mobile, quindi è molto importante per me aggiungere il meno possibile all'immagine della finestra mobile.
— 9ilsdx 9rvj 0lo

Se hai un'immagine con Maven e un jdk, allora Java sembra la migliore opzione per me .... perché consideri i pesi massimi Java in questo caso?
— Daniel Pryden,

Probabilmente vale la pena porre questa domanda su Stack Overflow e taggare con maven- sospetto che ci sia un modo migliore per fare ciò che stai cercando di fare all'interno di Maven stesso.
— Daniel Pryden,

Risposte:


10

XMLStarlet ( http://xmlstar.sourceforge.net/overview.php ) è scritto in C e usa libxml2e libxslt.

Dato il documento XML

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

è rootpossibile inserire un nodo secondario in

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

che produce

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

Inserendo molte cose (usando l'originale file.xmlin alto qui):

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

Questo produce

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

Per l'esempio nella domanda:

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

Risultato:

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

Inserimento di un file XML precedentemente preparato in una posizione nell'XML:

Supponendo che l'XML originale della domanda sia presente file.xmle che siano presenti i bit aggiuntivi che dovrebbero andare nel nuovo distributinManagementnodo new.xml(ma non il tag del nodo stesso), si potrebbe fare quanto segue per inserire new.xmlnel nodo radice:

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 sfuggirà automaticamente ai dati che devono essere salvati, come <e >caratteri. Il xml unescbit annulla l' escaping dei dati inseriti (in realtà elimina l'escaping dell'intero documento, che può essere o meno un problema) e xml foriformatta il documento XML risultante.

Il risultato è

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

Sono un po 'a disagio nel farlo in questo modo, "ma funziona".

Vedi anche questa domanda correlata su StackOverflow: /programming/29298507/xmlstarlet-xinclude-xslt


Sembra interessante, anche se per l'inserimento di più di un singolo tag la sintassi è piuttosto lunga. Solo che in Ubuntu si chiama 'xmlstarlet'. È possibile inserire il contenuto di un altro file come tag, supponendo che il contenuto sia un XML valido?
— 9ilsdx 9rvj 0lo,

@ 9ilsdx9rvj0lo Vedi risposta aggiornata.
— Kusalananda

"in realtà elimina l'intero documento, il che può essere o meno un problema". Sì enorme problema, tutto l'attuale & amp; non sono stati codificati e l'XML non è più valido :(
— rob

1

Trovo eccessivo installare java, perl o python nel sistema operativo a tale scopo (i miei script sono fatti in gitlab con immagini docker, quindi fare il mio lavoro con strumenti disponibili in maven: l'immagine 3.5-jdk-8 sarebbe un sogno).

probabilmente è ancora eccessivo, ma se ti preoccupi solo delle dimensioni del contenitore potresti usare un linguaggio molto leggero come Lua o Guile.

dai documenti Lua:

L'aggiunta di Lua a un'applicazione non la gonfia. Il tarball per Lua 5.3.4, che contiene il codice sorgente e la documentazione, richiede 297 KB compressi e 1,1 milioni non compressi. Il sorgente contiene circa 24000 righe di C. Sotto Linux a 64 bit, l'interprete Lua creato con tutte le librerie Lua standard richiede 246K e la libreria Lua ne prende 421K.


Vale la pena considerare semplicemente l'aggiunta di LUA al contenitore Mven, grazie per la punta.
— 9ilsdx 9rvj 0lo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.