Manipulasi baris perintah XML (skrip shell)

9

Bagaimana cara memanipulasi XML dari baris perintah dalam skrip shell?

Ada banyak perintah untuk memanipulasi data tabel, mengganti variabel lingkungan atau mengganti fragmen teks dengan regex, tetapi saya belum menemukan apa pun untuk XML.

Skrip build saya perlu menyisipkan tag dengan konten di dalam tag utama dari dokumen xml, dan saya merasa ini adalah kerja keras untuk menginstal java, perl atau python di OS untuk tujuan itu (skrip saya dikerjakan di gitlab dengan gambar docker, jadi melakukan pekerjaan saya dengan alat tersedia di maven: gambar 3,5-jdk-8 akan menjadi mimpi).

Saya tidak ingin memanipulasi XML dengan sed, meskipun dalam skrip build saya ini akan berhasil, karena itu jahat .

Contoh: Saya punya xml berikut:

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

Dan saya ingin menyisipkan blok berikut:

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

di dalam tag proyek (dan itu sepenuhnya tidak masalah apakah itu akan di awal atau di akhir.

9ilsdx 9rvj 0lo
sumber
memposting xml input Anda dan output yang diharapkan
RomanPerekhrest
Jadi persyaratan khusus untuk parser XML yang dapat dipanggil dari baris perintah yang tidak diimplementasikan dalam bahasa scripting utama, tetapi utilitas C atau C ++ (atau kompilasi lainnya) yang berdiri sendiri?
Kusalananda
@ Kusalanda saya telah menetapkan saya menjalankan scipts di dalam kontainer buruh pelabuhan, jadi yang paling penting bagi saya untuk menambahkan sesedikit mungkin ke gambar buruh pelabuhan.
9ilsdx 9rvj 0lo
Jika Anda memiliki gambar dengan maven dan jdk maka Java terdengar seperti pilihan terbaik bagi saya .... mengapa Anda menganggap Java kelas berat dalam kasus ini?
Daniel Pryden
Mungkin patut mengajukan pertanyaan ini pada Stack Overflow dan pemberian tag maven- Saya menduga ada cara yang lebih baik untuk melakukan apa yang Anda coba lakukan di dalam Maven sendiri.
Daniel Pryden

Jawaban:

10

XMLStarlet ( http://xmlstar.sourceforge.net/overview.php ) ditulis dalam C dan menggunakan libxml2dan libxslt.

Diberikan dokumen XML

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

sebuah subnode rootdapat disisipkan menggunakan

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

yang menghasilkan

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

Memasukkan banyak hal (menggunakan aslinya file.xmldi atas sini):

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

Ini menghasilkan

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

Sebagai contoh dalam pertanyaan:

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

Hasil:

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

Memasukkan file XML yang disiapkan sebelumnya di lokasi di XML:

Dengan asumsi XML asli dari pertanyaan sudah ada file.xmldan bit tambahan yang seharusnya ada di distributinManagementsimpul baru ada new.xml(tetapi bukan tag simpul itu sendiri), orang bisa melakukan hal berikut untuk memasukkan new.xmldalam simpul akar:

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 secara otomatis akan melarikan diri data yang perlu melarikan diri, seperti <dan >karakter. The xml unescbit unescapes data dimasukkan (sebenarnya unescapes seluruh dokumen, yang mungkin atau mungkin tidak menjadi masalah), dan xml fomemformat dokumen XML yang dihasilkan.

Hasilnya adalah

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

Saya sedikit tidak nyaman melakukannya dengan cara ini, "tetapi berhasil".

Lihat juga pertanyaan terkait ini di StackOverflow: /programming/29298507/xmlstarlet-xinclude-xslt

Kusalananda
sumber
Ini terlihat menarik, meskipun untuk memasukkan lebih dari satu tag tunggal sintaksinya cukup panjang. Hanya itu di ubuntu yang bernama 'xmlstarlet'. Apakah mungkin untuk memasukkan konten file lain sebagai tag, dengan asumsi konten tersebut adalah xml yang valid?
9ilsdx 9rvj 0lo
@ 9ilsdx9rvj0lo Lihat jawaban yang diperbarui.
Kusalananda
"Ini sebenarnya menghapus seluruh dokumen, yang mungkin atau mungkin tidak menjadi masalah". Yap masalah masif, semua yang ada & amp; tidak terenkripsi yang menyebabkan XML tidak lagi berlaku :(
rob
1

Saya menemukan itu adalah sebuah keharusan untuk menginstal java, perl atau python di OS untuk tujuan itu (skrip saya dilakukan di gitlab dengan gambar docker, jadi melakukan pekerjaan saya dengan alat yang tersedia di maven: gambar 3.5-jdk-8 akan menjadi mimpi).

mungkin masih berlebihan, tetapi jika Anda hanya peduli dengan ukuran wadah Anda bisa menggunakan bahasa yang sangat ringan seperti Lua atau Guile.

dari Lua docs:

Menambahkan Lua ke suatu aplikasi tidak membuatnya gembung. Tarball untuk Lua 5.3.4, yang berisi kode sumber dan dokumentasi, mengambil 297K terkompresi dan 1.1M terkompresi. Sumbernya berisi sekitar 24000 baris C. Di bawah Linux 64-bit, juru bahasa Lua yang dibangun dengan semua perpustakaan Lua standar membutuhkan 246K dan perpustakaan Lua membutuhkan 421K.

bruno cuconato
sumber
Layak mempertimbangkan hanya menambahkan LUA ke wadah pakar, terima kasih atas tipnya.
9ilsdx 9rvj 0lo