Scripting: apa yang paling mudah untuk mengekstraksi nilai dalam tag file XML?

14

Saya ingin membaca pom.xml ('Project Object Model' dari Maven) dan mengekstrak informasi versi. Berikut ini sebuah contoh:

<?xml version="1.0" encoding="UTF-8"?><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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>project-parent</artifactId>
    <name>project-parent</name>
    <version>1.0.74-SNAPSHOT</version>
    <dependencies>
        <dependency>
        <groupId>com.sybase.jconnect</groupId>
        <artifactId>jconnect</artifactId>
        <version>6.05-26023</version>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>1.5.2</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jdmk</groupId>
        <artifactId>jmxtools</artifactId>
        <version>1.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.easymock</groupId>
        <artifactId>easymock</artifactId>
        <version>2.4</version>
    </dependency>       
</dependencies>
</project>

Bagaimana saya bisa mengekstrak versi '1.0.74-SNAPSHOT' dari atas?

Senang bisa melakukannya menggunakan sed bash scripting sederhana atau awk. Kalau tidak, python sederhana lebih disukai.

SUNTING

  1. Paksaan

    Kotak linux ada di lingkungan perusahaan jadi saya hanya bisa menggunakan alat yang sudah diinstal (bukan saya tidak bisa meminta utilitas seperti xml2, tapi saya harus melalui banyak red-tape). Beberapa solusi sangat baik (pelajari beberapa trik baru), tetapi mereka mungkin tidak berlaku karena lingkungan terbatas

  2. daftar xml diperbarui

    Saya menambahkan tag dependensi ke daftar asli. Ini akan menunjukkan beberapa solusi hacky mungkin tidak berfungsi dalam kasus ini

  3. Distro

    Distro yang saya gunakan adalah RHEL4

Anthony Kong
sumber
Apakah ini stackoverflow.com/questions/29004/... cukup?
bbaja42
Tidak juga. Ada banyak tag versi di xml (mis. Di bawah tag dependensi). Saya hanya ingin '/ proyek / versi'
Anthony Kong
Alat dan pustaka terkait xml mana yang tersedia? Apakah solvsi berbasis jvm baik-baik saja?
Vi.
Sejauh ini saya dapat memberi tahu xml2, xmlgrep dan modul XML perl tidak ada. Sebagian besar utilitas baris perintah unix hadir. Distronya adalah Redhat EL 4.
Anthony Kong
(Saya tidak bisa menambahkan komentar jadi saya harus menjawab sebagai jawaban, agak berlebihan). Beberapa jawaban bagus dapat ditemukan di sini ..... stackoverflow.com/questions/2735548/…
JStrahl

Jawaban:

17

xml2 dapat mengonversi xml ke / dari format berorientasi baris:

xml2 < pom.xml  | grep /project/version= | sed 's/.*=//'
Vi.
sumber
6

Cara lain: xmlgrep dan XPath:

xmlgrep --text_only '/project/version' pom.xml

Kerugian: lambat

Vi.
sumber
perintah diperbarui kexml_grep
GAD3R
6

Menggunakan python

$ python -c 'from xml.etree.ElementTree import ElementTree; print ElementTree(file="pom.xml").findtext("{http://maven.apache.org/POM/4.0.0}version")'
1.0.74-SNAPSHOT

Menggunakan xmlstarlet

$ xml sel -N x="http://maven.apache.org/POM/4.0.0" -t -m 'x:project/x:version' -v . pom.xml
1.0.74-SNAPSHOT

Menggunakan xmllint

$ echo -e 'setns x=http://maven.apache.org/POM/4.0.0\ncat /x:project/x:version/text()' | xmllint --shell pom.xml | grep -v /
1.0.74-SNAPSHOT
kev
sumber
cat (//x:version)[1]/text()saat menggunakan xmllintjuga bekerja!
kev
5

Cara Clojure. Hanya membutuhkan jvm dengan file jar khusus:

java -cp clojure.jar clojure.main -e "(use 'clojure.xml) (->> (java.io.File. \"pom.xml\") (clojure.xml/parse) (:content) (filter #(= (:tag %) :version)) (first) (:content) (first) (println))"

Cara scala:

java -Xbootclasspath/a:scala-library.jar -cp scala-compiler.jar scala.tools.nsc.MainGenericRunner -e 'import scala.xml._; println((XML.load(new java.io.FileInputStream("pom.xml")) match { case <project>{children @ _*}</project> => for (i <- children if (i  match { case <version>{children @ _*}</version> => true; case _ => false;  }))  yield i })(0) match { case <version>{Text(x)}</version> => x })'

Cara asyik:

java -classpath groovy-all.jar groovy.ui.GroovyMain -e 'println (new XmlParser().parse(new File("pom.xml")).value().findAll({ it.name().getLocalPart()=="version" }).first().value().first())'
Vi.
sumber
Ini luar biasa! Ide yang hebat!
Anthony Kong
4

Berikut alternatif di Perl

$ perl -MXML::Simple -e'print XMLin("pom.xml")->{version}."\n"'
1.0.74-SNAPSHOT

Ini bekerja dengan contoh yang direvisi / diperluas dalam pertanyaan yang memiliki beberapa elemen "versi" pada kedalaman yang berbeda.

RedGrittyBrick
sumber
Lambat, (meskipun lebih cepat dari xmlgrep)
Vi.
3

Cara hacky :

perl -e '$_ = join "", <>; m!<project[^>]*>.*\n(?:    |\t)<version[^>]*>\s*([^<]+?)\s*</version>.*</project>!s and print "$1\n"' pom.xml

Mengandalkan lekukan yang benar dari yang dibutuhkan <version>

Vi.
sumber
Terima kasih atas sarannya, tetapi sayangnya itu tidak akan mengembalikan apa yang saya inginkan. Silakan lihat model pom yang diperbarui.
Anthony Kong
Mengembalikan "1.0.74-SNAPSHOT". Perhatikan bahwa saya mengubah skrip setelah membaca tentang banyak <version>hal.
Vi.
Catatan: solusi ini disediakan "hanya untuk bersenang-senang" dan tidak dimaksudkan untuk digunakan dalam produk yang sebenarnya. Lebih baik gunakan xml2 / xmlgrep / XML :: Solusi sederhana.
Vi.
Terima kasih! meskipun ini 'hanya untuk bersenang-senang' tetapi mungkin ini adalah solusi 'paling cocok' sejauh ini karena memiliki jumlah dependensi minimum: Hanya memerlukan perl ;-)
Anthony Kong
Bagaimana dengan melakukannya dari Jawa? Menggunakan file pom menyiratkan memiliki JVM diinstal.
Vi.
3

Kerjakan solusi satu-liner yang sangat canggung

python -c "from xml.dom.minidom import parse;dom = parse('pom.xml');print [n for n in dom.getElementsByTagName('version') if n.parentNode == dom.childNodes[0]][0].toxml()" | sed -e "s/.*>\(.*\)<.*/\1/g"

Sed pada akhirnya sangat jelek tetapi saya tidak dapat mencetak teks dari node dengan mindom saja.

Perbarui dari _Vi :

Versi Python yang kurang rapi:

python -c "from xml.dom.minidom import parse;dom = parse('pom.xml');print [i.childNodes.item(0).nodeValue for i in dom.firstChild.childNodes if i.nodeName == 'version'].pop()"

Perbarui dari saya

Versi lain:

    python -c "from  xml.dom.minidom import parse;dom = parse('pom.xml');print [n.firstChild.data for n in dom.childNodes[0].childNodes if n.firstChild and n.tagName == 'version']"
Anthony Kong
sumber
2

Cara XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>

        <xsl:template match="/">
                <xsl:for-each select="*[local-name()='project']">
                    <xsl:for-each select="*[local-name()='version']">
                        <xsl:value-of select="text()"/>
                    </xsl:for-each>
                </xsl:for-each>
        </xsl:template>
</xsl:stylesheet>
xalan -xsl x.xsl -in pom.xml
Vi.
sumber
Jika xsltproc ada di sistem Anda, dan mungkin libxslt ada di RHEL4, maka Anda dapat menggunakannya dan stylesheet di atas untuk menampilkan tag, yaitu xsltproc x.xsl prom.xsl.
fpmurphy
2

jika "Ada banyak tag versi di xml" maka Anda lebih baik melupakannya dengan "alat sederhana" dan regexps, itu tidak akan berhasil.

coba python ini (tidak ada dependensi):

from xml.dom.minidom import parse

dom = parse('pom.xml')
project = dom.getElementsByTagName('project')[0]
for node in project.childNodes:
    if node.nodeType == node.ELEMENT_NODE and node.tagName == 'version':
        print node.firstChild.nodeValue
Samus_
sumber
Apa sebenarnya yang dilakukan skrip ini?
Simon Sheehan
itu memuat XML sebagai struktur DOM menggunakan implementasi minidom Python: docs.python.org/library/xml.dom.minidom.html idenya adalah untuk mengambil tag <project> yang unik dan kemudian beralih di atas simpul anaknya (langsung hanya untuk anak-anak) untuk menemukan tag <version> yang kami cari dan bukan tag lain dengan nama yang sama di tempat lain.
Samus_
1

Berikut ini adalah satu-liner menggunakan sed:

sed '/<dependencies>/,/<\/dependencies>/d;/<version>/!d;s/ *<\/\?version> *//g' pom.xml
chickenkiller
sumber
1
Bergantung pada tidak adanya parameter dalam elemen dan tambahan <version>itu hanya bisa di dalam dependensi.
Vi.
0
Return_text_val=$(xmllint --xpath "//*[local-name()='$TagElmnt']" $FILE )

Di sini, coba ini:

$TagElmnt - TagName
$FILE - xml file to parse
Vijayababu
sumber
0

Saya tahu pertanyaan Anda mengatakan Linux, tetapi jika Anda perlu melakukan ini di Windows tanpa memerlukan alat pihak ke-3 sehingga Anda dapat memasukkannya ke dalam file batch, Powershell dapat mengekstrak setiap simpul dari file pom.xml Anda seperti itu :

powershell -Command "& {select-xml //pom:project/pom:properties/pom:mypluginversion -path pom.xml -Namespace  @{pom='http://maven.apache.org/POM/4.0.0'} | foreach {$_.Node.Innerxml}}" > myPluginVersion.txt
Peter Lubczynski
sumber
Powershell sekarang open source dan berjalan di Linux dan platform lainnya. Kami menggunakannya untuk membangun dalam preferensi untuk bash, cygwin dan ming64.
Charlweed
0
sed -n "/<name>project-parent/{n;s/.*>\(.*\)<.*/\1/p;q}" pom.xml

The -npilihan menghindari pencetakan garis yang tidak cocok; pertandingan pertama ( /.../) ada di baris sebelum yang berisi teks yang diinginkan; yang nperintah melompat ke baris berikutnya, di mana sekstrak info yang relevan melalui grup menangkap ( \(...\)), dan backreference ( \1). pmencetak,q berhenti.

SΛLVΘ
sumber
2
Bisakah Anda memperluas jawaban Anda untuk menjelaskan ini? Terima kasih.
fixer1234
0

awk berfungsi dengan baik tanpa menggunakan alat tambahan.
cat pod.xml

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.networks.app</groupId>
  <artifactId>operation-platform</artifactId>
  <version>1.0.0</version>
  <packaging>tar.xz</packaging>
  <description>POM was created by Sonatype Nexus</description>
</project>

cara sederhana dan mudah dibaca untuk mendapatkan nilai <packaging>tag:

cat pod.xml | awk -F'[<>]' '/packaging/{print $3}'
pengguna5723841
sumber