Manipulation der XML-Befehlszeile (Shell-Skript)

9

Wie manipuliere ich XML über die Befehlszeile im Shell-Skript?

Es gibt viele Befehle zum Bearbeiten von Tabellendaten, zum Ersetzen von Umgebungsvariablen oder zum Ersetzen von Textfragmenten durch Regex, aber ich habe nichts für XML gefunden.

Mein Build-Skript muss ein Tag mit Inhalt in das Haupt-Tag des XML-Dokuments einfügen, und ich finde es ein Overkill, zu diesem Zweck Java, Perl oder Python in OS zu installieren (meine Skripte werden in gitlab mit Docker-Images erstellt Mein Job mit Tools, die in Maven verfügbar sind: 3.5-JDK-8-Bild wäre ein Traum.

Ich möchte XML nicht mit sed manipulieren, obwohl es in meinem Build-Skript funktionieren würde, weil es böse ist .

Beispiel: Ich habe die folgende 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>  

Und ich möchte folgenden Block einfügen:

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

innerhalb des Projekt-Tags (und es spielt keine Rolle, ob es am Anfang oder am Ende sein wird.

9ilsdx 9rvj 0lo
quelle
Veröffentlichen Sie
Die spezifischen Anforderungen gelten also für einen XML-Parser, der über die Befehlszeile aufgerufen werden kann und nicht in einer der wichtigsten Skriptsprachen implementiert ist, sondern in einem freistehenden C- oder C ++ - (oder einem anderen kompilierten) Dienstprogramm?
Kusalananda
@Kusalanda Ich habe angegeben, dass ich Skripte in Docker-Containern ausführe. Daher ist es für mich am wichtigsten, dem Docker-Image so wenig wie möglich hinzuzufügen.
9ilsdx 9rvj 0lo
Wenn Sie ein Bild mit Maven und einem JDK haben, klingt Java für mich nach der besten Option. Warum betrachten Sie Java in diesem Fall als Schwergewicht?
Daniel Pryden
Es lohnt sich wahrscheinlich, diese Frage zum Stapelüberlauf zu stellen und mit zu markieren maven- ich vermute, es gibt einen besseren Weg, um das zu tun, was Sie in Maven selbst versuchen.
Daniel Pryden

Antworten:

10

XMLStarlet ( http://xmlstar.sourceforge.net/overview.php ) ist in C geschrieben und verwendet libxml2und libxslt.

Angesichts des XML-Dokuments

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

Ein Unterknoten rootkann mit eingefügt werden

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

was produziert

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

Viele Dinge einfügen (hier das Original file.xmloben verwenden):

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

Dies erzeugt

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

Für das Beispiel in der Frage:

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

Ergebnis:

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

Einfügen einer zuvor vorbereiteten XML-Datei an einer Stelle im XML:

Angenommen, das ursprüngliche XML aus der Frage ist in file.xmlund die zusätzlichen Bits, die in den neuen distributinManagementKnoten eingefügt werden sollen, sind in new.xml(aber nicht das Knoten-Tag selbst), könnte man Folgendes tun , um es new.xmlin den Wurzelknoten einzufügen :

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 maskiert automatisch Daten, die maskiert werden müssen, wie z. B. <und >Zeichen. Das xml unescBit entkoppelt die eingefügten Daten (es entkapselt tatsächlich das gesamte Dokument, was möglicherweise ein Problem darstellt oder nicht) und xml foformatiert das resultierende XML-Dokument neu.

Das Ergebnis ist

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

Ich bin ein bisschen unruhig, wenn ich es so mache, "aber es funktioniert".

Siehe auch diese verwandte Frage zu StackOverflow: /programming/29298507/xmlstarlet-xinclude-xslt

Kusalananda
quelle
Es sieht interessant aus, obwohl die Syntax für das Einfügen von mehr als einem einzelnen Tag ziemlich lang ist. Nur das in Ubuntu heißt 'xmlstarlet'. Ist es möglich, den Inhalt einer anderen Datei als Tag einzufügen, vorausgesetzt, der Inhalt ist eine gültige XML?
9ilsdx 9rvj 0lo
@ 9ilsdx9rvj0lo Siehe aktualisierte Antwort.
Kusalananda
"Es entkoppelt tatsächlich das gesamte Dokument, was ein Problem sein kann oder nicht." Ja, massives Problem, alle vorhandenen & amp; wurden nicht codiert, was dazu führte, dass XML nicht mehr gültig war :(
rob
1

Ich finde es übertrieben, Java, Perl oder Python zu diesem Zweck in OS zu installieren (meine Skripte werden in Gitlab mit Docker-Images erstellt, daher wäre es ein Traum, meine Arbeit mit den in maven verfügbaren Tools zu erledigen: 3.5-jdk-8-Image).

Es ist wahrscheinlich immer noch übertrieben, aber wenn Sie sich nur mit der Größe des Containers befassen, können Sie eine sehr leichte Sprache wie Lua oder Guile verwenden.

aus den Lua-Dokumenten:

Durch Hinzufügen von Lua zu einer Anwendung wird diese nicht aufgebläht. Der Tarball für Lua 5.3.4, der Quellcode und Dokumentation enthält, benötigt 297 KB komprimiert und 1,1 MB unkomprimiert. Die Quelle enthält ungefähr 24000 Zeilen C. Unter 64-Bit-Linux benötigt der Lua-Interpreter, der mit allen Standard-Lua-Bibliotheken erstellt wurde, 246 KB und die Lua-Bibliothek 421 KB.

bruno cuconato
quelle
Es lohnt sich, einfach LUA in den Maven-Container zu geben, danke für den Tipp.
9ilsdx 9rvj 0lo