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.