Ini benar-benar hanya sebuah penjelasan dari jawaban Yuzem , tetapi saya tidak merasa bahwa banyak pengeditan ini harus dilakukan kepada orang lain, dan komentar tidak mengizinkan pemformatan, jadi ...
rdom (){local IFS=\> ; read -d \< E C ;}
Sebut saja "read_dom" alih-alih "rdom", kosongkan sedikit dan gunakan variabel yang lebih panjang:
Oke jadi itu mendefinisikan fungsi yang disebut read_dom. Baris pertama membuat IFS (pemisah bidang input) lokal untuk fungsi ini dan mengubahnya ke>. Itu berarti bahwa ketika Anda membaca data alih-alih secara otomatis dipisah pada ruang, tab atau baris baru itu terbagi pada '>'. Baris berikutnya mengatakan untuk membaca input dari stdin, dan bukannya berhenti di baris baru, berhentilah ketika Anda melihat karakter '<' (the -d untuk flag pembatas). Apa yang dibaca kemudian dibagi menggunakan IFS dan ditugaskan ke variabel ENTITY dan CONTENT. Jadi, ambil yang berikut ini:
<tag>value</tag>
Panggilan pertama untuk read_dommendapatkan string kosong (karena '<' adalah karakter pertama). Itu terpecah oleh IFS menjadi hanya '', karena tidak ada karakter '>'. Baca lalu berikan string kosong ke kedua variabel. Panggilan kedua mendapatkan string 'tag> value'. Itu kemudian dibagi oleh IFS menjadi dua kolom 'tag' dan 'value'. Baca lalu tetapkan variabel seperti: ENTITY=tagdan CONTENT=value. Panggilan ketiga mendapat string '/ tag>'. Itu terpecah oleh IFS menjadi dua bidang '/ tag' dan ''. Baca lalu tetapkan variabel seperti: ENTITY=/tagdan CONTENT=. Panggilan keempat akan mengembalikan status bukan nol karena kami telah mencapai akhir file.
Sekarang loop while-nya membersihkan sedikit agar sesuai dengan yang di atas:
while read_dom;doif[[ $ENTITY ="title"]];then
echo $CONTENT
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
Baris pertama hanya mengatakan, "sementara fungsi read_dom mengembalikan status nol, lakukan hal berikut." Baris kedua memeriksa apakah entitas yang baru saja kita lihat adalah "judul". Baris berikutnya menggemakan konten tag. Empat garis keluar. Jika itu bukan entitas judul maka loop berulang di baris keenam. Kami mengarahkan "xhtmlfile.xhtml" ke input standar (untuk read_domfungsi) dan mengarahkan output standar ke "titleOfXHTMLPage.txt" (gema dari sebelumnya dalam loop).
Sekarang diberi yang berikut (mirip dengan apa yang Anda dapatkan dari daftar ember di S3) untuk input.xml:
Jadi jika kita menulis sebuah whileloop seperti Yuzem:
while read_dom;doif[[ $ENTITY ="Key"]];then
echo $CONTENT
fidone< input.xml
Kami akan mendapatkan daftar semua file di keranjang S3.
EDIT
Jika karena alasan tertentu local IFS=\>tidak berhasil untuk Anda dan Anda menyetelnya secara global, Anda harus mengatur ulang di akhir fungsi seperti:
$ cat example.xml |./bash_xml.sh
bar type is: metal
foo size is:1789
EDIT 3 pengguna lain mengatakan mereka mengalami masalah dengan itu di FreeBSD dan menyarankan menyimpan status keluar dari membaca dan mengembalikannya di akhir read_dom seperti:
Jika Anda membuat IFS (pemisah bidang input) global, Anda harus meresetnya kembali ke nilai aslinya di akhir, saya mengedit jawaban untuk memilikinya. Kalau tidak, setiap input lain yang Anda lakukan nanti dalam skrip Anda akan kacau. Saya menduga alasan lokal tidak berfungsi untuk Anda adalah karena Anda menggunakan bash dalam mode kompatibilitas (seperti shbang Anda adalah #! / Bin / sh) atau ini adalah versi kuno dari bash.
chad
30
Hanya karena Anda dapat menulis parser Anda sendiri, bukan berarti Anda harus melakukannya.
Stephen Niedzielski
1
@chad tentu mengatakan sesuatu tentang AWS' alur kerja / implementasi yang saya sedang mencari jawaban untuk 'pesta xml' juga wget isi ember S3!
Alastair
2
@Alastair lihat github.com/chad3814/s3scripts untuk satu set skrip bash yang kita gunakan untuk memanipulasi objek S3
chad
5
Menetapkan IFS dalam variabel lokal rapuh dan tidak perlu. Lakukan IFS=\< read ...saja:, yang hanya akan mengatur IFS untuk panggilan baca. (Perhatikan bahwa saya sama sekali tidak mendukung praktik penggunaan readuntuk mem-parsing xml, dan saya percaya melakukan hal itu penuh dengan bahaya dan harus dihindari.)
William Pursell
64
Anda dapat melakukannya dengan sangat mudah hanya menggunakan bash. Anda hanya perlu menambahkan fungsi ini:
rdom (){local IFS=\> ; read -d \< E C ;}
Sekarang Anda dapat menggunakan rdom seperti baca tetapi untuk dokumen html. Ketika dipanggil rdom akan menetapkan elemen ke variabel E dan konten ke var C.
Misalnya, untuk melakukan apa yang ingin Anda lakukan:
while rdom;doif[[ $E = title ]];then
echo $C
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
Bisakah Anda menjelaskan hal ini? Saya berani bertaruh bahwa itu sangat jelas bagi Anda .. dan ini bisa menjadi jawaban yang bagus - jika saya tahu apa yang Anda lakukan di sana .. dapatkah Anda memecahnya sedikit lagi, mungkin menghasilkan beberapa sampel output?
Alex Grey
1
Dipercayai dengan aslinya - one-liner ini sangat elegan dan menakjubkan.
maverick
1
hack besar, tetapi saya harus menggunakan tanda kutip ganda seperti gema "$ C" untuk mencegah ekspansi shell dan interpretasi yang benar dari garis akhir (tergantung pada pengkondisiannya)
user311174
8
Parsing XML dengan grep dan awk tidak oke . Ini mungkin kompromi yang dapat diterima jika XML cukup sederhana dan Anda tidak punya banyak waktu, tetapi itu tidak bisa disebut solusi yang baik.
peterh
59
Alat baris perintah yang dapat dipanggil dari skrip shell meliputi:
4xpath - pembungkus baris perintah di sekitar paket 4Suite Python
xpath - pembungkus baris perintah di sekitar perpustakaan XPath Perl
Xidel - Bekerja dengan URL serta file. Juga bekerja dengan JSON
Saya juga menggunakan xmllint dan xsltproc dengan sedikit skrip transformasi XSL untuk melakukan pemrosesan XML dari baris perintah atau dalam skrip shell.
Di mana saya dapat mengunduh 'xpath' atau '4xpath' dari?
Opher
3
ya, suara / permintaan kedua - tempat untuk mengunduh alat-alat itu, atau apakah Anda maksudnya harus menulis bungkus secara manual? Saya lebih suka tidak membuang waktu melakukan itu kecuali perlu.
David
4
sudo apt-get install libxml-xpath-perl
Andrew Wagner
22
Anda dapat menggunakan utilitas xpath. Itu diinstal dengan paket Perl XML-XPath.
Pemakaian:
/usr/bin/xpath [filename] query
atau XMLStarlet . Untuk menginstalnya di opensuse gunakan:
Menggunakan xml starlet jelas merupakan pilihan yang lebih baik daripada menulis serializer sendiri (seperti yang disarankan dalam jawaban lain).
Bruno von Paris
Pada banyak sistem, xpathyang sudah diinstal sebelumnya tidak cocok untuk digunakan sebagai komponen dalam skrip. Lihat misalnya stackoverflow.com/questions/15461737/… untuk penjelasan.
mulai dari jawaban chad, berikut ini adalah solusi kerja COMPLETE untuk mengurai UML, dengan penanganan komentar yang tepat, dengan hanya 2 fungsi kecil (lebih dari 2 bu Anda dapat mencampur semuanya). Saya tidak mengatakan chad tidak berfungsi sama sekali, tetapi memiliki terlalu banyak masalah dengan file XML yang diformat dengan buruk: Jadi Anda harus sedikit lebih rumit untuk menangani komentar dan spasi yang salah tempat / CR / TAB / dll.
Tujuan dari jawaban ini adalah untuk memberikan fungsi ready-2-use, out of the box untuk siapa saja yang membutuhkan parsing UML tanpa alat kompleks menggunakan perl, python atau apa pun. Bagi saya, saya tidak dapat menginstal cpan, atau modul perl untuk OS produksi lama yang saya kerjakan, dan python tidak tersedia.
Pertama, definisi kata-kata UML yang digunakan dalam posting ini:
oh dan Anda akan memerlukan beberapa variabel dinamis pewarnaan rapi untuk didefinisikan pada awalnya, dan diekspor juga:
set-a
TERM=xterm-256colorcase ${UNAME}in
AIX|SunOS)
M=$(${print}'\033[1;35m')
m=$(${print}'\033[0;35m')END=$(${print}'\033[0m');;*)
m=$(tput setaf 5)
M=$(tput setaf 13)# END=$(tput sgr0) # issue on Linux: it can produces ^[(B instead of ^[[0m, more likely when using screenrcEND=$(${print}'\033[0m');;esac# 24 shades of grey:for i in $(seq 023);doeval g$i="$(${print} \"\\033\[38\;5\;$((232 + i))m\")";done# another way of having an array of 5 shades of grey:
declare -a colorNums=(238240243248254)for num in01234;do nn[$num]=$(${print}"\033[38;5;${colorNums[$num]}m"); NN[$num]=$(${print}"\033[48;5;${colorNums[$num]}m");done# piped decolorization:
DECOLORIZE='eval sed "s,${END}\[[0-9;]*[m|K],,g"'
Cara memuat semua itu:
Entah Anda tahu cara membuat fungsi dan memuatnya melalui FPATH (ksh) atau emulasi FPATH (bash)
Jika tidak, cukup salin / tempel semua yang ada di baris perintah.
Bagaimana cara kerjanya:
xml_read [-cdlp][-x command <-a attribute>]<file.xml>[tag |"any"][attributes ..|"content"]-c = NOCOLOR
-d =Debug-l = LIGHT (no \"attribute=\" printed)-p = FORCE PRINT (whenno attributes given)-x = apply a command on an attribute andprint the result instead of the former value,in green color
(no attribute given will load their values into your shell as $ATTRIBUTE=value;use'-p' to print them as well)
xml_read server.xml title content # print content between <title></title>
xml_read server.xml Connector port # print all port values from Connector tags
xml_read server.xml any port # print all port values from any tags
Dengan mode Debug (-d) komentar dan atribut yang diuraikan dicetak ke stderr
Saya mencoba menggunakan dua fungsi di atas yang menghasilkan yang berikut ./read_xml.sh: line 22: (-1): substring expression < 0:?
khmarbaise
Baris 22:[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
khmarbaise
maaf khmarbaise, ini adalah fungsi bash shell. Jika Anda ingin mengadaptasi mereka sebagai skrip shell, Anda tentu harus mengharapkan beberapa adaptasi kecil! Juga fungsi yang diperbarui menangani kesalahan Anda;)
pemulung
4
Saya tidak mengetahui adanya alat parsing XML shell murni. Jadi Anda kemungkinan besar akan membutuhkan alat yang ditulis dalam bahasa lain.
Modul XML :: Twig Perl saya dilengkapi dengan alat seperti ini:, di xml_grepmana Anda mungkin akan menulis apa yang Anda inginkan xml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt( -topsi memberi Anda hasilnya sebagai teks, bukan xml)
Alat baris perintah lainnya adalah Xidel baru saya . Ini juga mendukung XPath 2 dan XQuery, bertentangan dengan xpath / xmlstarlet yang telah disebutkan.
Setelah beberapa penelitian untuk terjemahan antara Linux dan format Windows jalur file dalam file XML saya menemukan tutorial dan solusi menarik pada:
Walaupun ada beberapa utilitas konsol siap pakai yang mungkin melakukan apa yang Anda inginkan, mungkin akan memakan waktu lebih sedikit untuk menulis beberapa baris kode dalam bahasa pemrograman tujuan umum seperti Python yang dapat dengan mudah diperluas dan disesuaikan dengan kebutuhanmu.
Berikut ini adalah skrip python yang digunakan lxmluntuk parsing - dibutuhkan nama file atau URL sebagai parameter pertama, ekspresi XPath sebagai parameter kedua, dan mencetak string / node yang cocok dengan ekspresi yang diberikan.
Contoh 1
#!/usr/bin/env pythonimport sys
from lxml import etree
tree = etree.parse(sys.argv[1])
xpath_expression = sys.argv[2]# a hack allowing to access the# default namespace (if defined) via the 'p:' prefix # E.g. given a default namespaces such as 'xmlns="http://maven.apache.org/POM/4.0.0"'# an XPath of '//p:module' will return all the 'module' nodes
ns = tree.getroot().nsmap
if ns.keys()andNonein ns:
ns['p']= ns.pop(None)# end of hack for e in tree.xpath(xpath_expression, namespaces=ns):if isinstance(e, str):print(e)else:print(e.text and e.text.strip()or etree.tostring(e, pretty_print=True))
lxmldapat diinstal dengan pip install lxml. Di ubuntu Anda bisa menggunakan sudo apt install python-lxml.
Catatan : Jika XML Anda memiliki namespace default tanpa awalan (mis. xmlns=http://abc...) Maka Anda harus menggunakan pawalan (disediakan oleh 'hack') dalam ekspresi Anda, misalnya //p:moduleuntuk mendapatkan modul dari pom.xmlfile. Jika pawalan sudah dipetakan dalam XML Anda, maka Anda harus memodifikasi skrip untuk menggunakan awalan lain.
Contoh 2
Skrip satu kali yang melayani tujuan sempit mengekstraksi nama modul dari file apache maven. Perhatikan bagaimana nama simpul ( module) diawali dengan namespace default {http://maven.apache.org/POM/4.0.0}:
Ini luar biasa ketika Anda ingin menghindari menginstal paket tambahan atau tidak memiliki akses. Pada mesin build, saya dapat membenarkan pip installover apt-getatau yumpanggilan ekstra . Terima kasih!
E. Moffat
0
Metode Yuzem dapat ditingkatkan dengan membalik urutan <dan >tanda - tanda dalam rdomfungsi dan tugas variabel, sehingga:
rdom (){local IFS=\> ; read -d \< E C ;}
menjadi:
rdom (){local IFS=\< ; read -d \> C E ;}
Jika parsing tidak dilakukan seperti ini, tag terakhir dalam file XML tidak pernah tercapai. Ini bisa bermasalah jika Anda berniat untuk menghasilkan file XML lain di akhir whileloop.
Meskipun sepertinya "tidak pernah menguraikan XML, JSON ... dari bash tanpa alat yang tepat" adalah saran yang bagus, saya tidak setuju. Jika ini adalah pekerjaan sampingan, itu adalah pinggang untuk mencari alat yang tepat, kemudian mempelajarinya ... Awk dapat melakukannya dalam hitungan menit. Program saya harus mengerjakan semua data yang disebutkan di atas dan lebih banyak lagi. Sial, saya tidak ingin menguji 30 alat untuk mem-parsing 5-7-10 format yang berbeda yang saya butuhkan jika saya dapat mengatasi masalah dalam hitungan menit. Saya tidak peduli dengan XML, JSON atau apa pun! Saya butuh solusi tunggal untuk semuanya.
Sebagai contoh: Program SmartHome saya mengelola rumah kami. Saat melakukannya, ia membaca sejumlah besar data dalam berbagai format berbeda yang tidak dapat saya kendalikan. Saya tidak pernah menggunakan alat khusus yang berdedikasi karena saya tidak ingin menghabiskan lebih dari beberapa menit untuk membaca data yang saya butuhkan. Dengan penyesuaian FS dan RS, solusi awk ini berfungsi sempurna untuk semua format teks. Tapi, itu mungkin bukan jawaban yang tepat ketika tugas utama Anda adalah bekerja terutama dengan banyak data dalam format itu!
Masalah parsing XML dari bash yang saya hadapi kemarin. Inilah cara saya melakukannya untuk format data hierarkis apa pun. Sebagai bonus - saya menetapkan data langsung ke variabel dalam skrip bash.
Agar lebih mudah dibaca, saya akan menyajikan solusi secara bertahap. Dari data tes OP, saya membuat file: test.xml
Parsing mengatakan XML dalam bash dan mengekstraksi data dalam 90 karakter:
Saya biasanya menggunakan versi yang lebih mudah dibaca karena lebih mudah untuk dimodifikasi dalam kehidupan nyata karena saya sering perlu menguji secara berbeda:
Saya tidak peduli bagaimana formatnya. Saya hanya mencari solusi paling sederhana. Dalam kasus khusus ini, saya dapat melihat dari data bahwa baris baru adalah pemisah rekaman (RS) dan bidang pembatas <> (FS). Dalam kasus asli saya, saya memiliki pengindeksan rumit dari 6 nilai dalam dua catatan, yang berkaitan dengan mereka, temukan ketika data ada ditambah bidang (catatan) mungkin atau mungkin tidak ada. Butuh 4 baris awk untuk menyelesaikan masalah dengan sempurna. Jadi, sesuaikan ide dengan setiap kebutuhan sebelum menggunakannya!
Bagian kedua hanya terlihat ada string yang diinginkan dalam garis (RS) dan jika demikian, mencetak bidang yang diperlukan (FS). Di atas butuh waktu sekitar 30 detik untuk menyalin dan beradaptasi dari perintah terakhir yang saya gunakan dengan cara ini (4 kali lebih lama). Dan itu dia! Dilakukan dalam 90 karakter.
Tapi, saya selalu perlu memasukkan data ke dalam variabel dalam skrip saya. Saya pertama kali menguji konstruksi seperti:
Dalam beberapa kasus saya menggunakan printf daripada print. Ketika saya melihat semuanya terlihat baik, saya hanya selesai menetapkan nilai ke variabel. Saya tahu banyak yang berpikir "eval" adalah "jahat", tidak perlu berkomentar :) Trik bekerja dengan baik pada keempat jaringan saya selama bertahun-tahun. Tetapi teruslah belajar jika Anda tidak mengerti mengapa ini bisa menjadi praktik yang buruk! Termasuk tugas variabel bash dan spasi yang cukup, solusi saya perlu 120 karakter untuk melakukan semuanya.
Jawaban:
Ini benar-benar hanya sebuah penjelasan dari jawaban Yuzem , tetapi saya tidak merasa bahwa banyak pengeditan ini harus dilakukan kepada orang lain, dan komentar tidak mengizinkan pemformatan, jadi ...
Sebut saja "read_dom" alih-alih "rdom", kosongkan sedikit dan gunakan variabel yang lebih panjang:
Oke jadi itu mendefinisikan fungsi yang disebut read_dom. Baris pertama membuat IFS (pemisah bidang input) lokal untuk fungsi ini dan mengubahnya ke>. Itu berarti bahwa ketika Anda membaca data alih-alih secara otomatis dipisah pada ruang, tab atau baris baru itu terbagi pada '>'. Baris berikutnya mengatakan untuk membaca input dari stdin, dan bukannya berhenti di baris baru, berhentilah ketika Anda melihat karakter '<' (the -d untuk flag pembatas). Apa yang dibaca kemudian dibagi menggunakan IFS dan ditugaskan ke variabel ENTITY dan CONTENT. Jadi, ambil yang berikut ini:
Panggilan pertama untuk
read_dom
mendapatkan string kosong (karena '<' adalah karakter pertama). Itu terpecah oleh IFS menjadi hanya '', karena tidak ada karakter '>'. Baca lalu berikan string kosong ke kedua variabel. Panggilan kedua mendapatkan string 'tag> value'. Itu kemudian dibagi oleh IFS menjadi dua kolom 'tag' dan 'value'. Baca lalu tetapkan variabel seperti:ENTITY=tag
danCONTENT=value
. Panggilan ketiga mendapat string '/ tag>'. Itu terpecah oleh IFS menjadi dua bidang '/ tag' dan ''. Baca lalu tetapkan variabel seperti:ENTITY=/tag
danCONTENT=
. Panggilan keempat akan mengembalikan status bukan nol karena kami telah mencapai akhir file.Sekarang loop while-nya membersihkan sedikit agar sesuai dengan yang di atas:
Baris pertama hanya mengatakan, "sementara fungsi read_dom mengembalikan status nol, lakukan hal berikut." Baris kedua memeriksa apakah entitas yang baru saja kita lihat adalah "judul". Baris berikutnya menggemakan konten tag. Empat garis keluar. Jika itu bukan entitas judul maka loop berulang di baris keenam. Kami mengarahkan "xhtmlfile.xhtml" ke input standar (untuk
read_dom
fungsi) dan mengarahkan output standar ke "titleOfXHTMLPage.txt" (gema dari sebelumnya dalam loop).Sekarang diberi yang berikut (mirip dengan apa yang Anda dapatkan dari daftar ember di S3) untuk
input.xml
:dan loop berikut:
Anda harus mendapatkan:
Jadi jika kita menulis sebuah
while
loop seperti Yuzem:Kami akan mendapatkan daftar semua file di keranjang S3.
EDIT Jika karena alasan tertentu
local IFS=\>
tidak berhasil untuk Anda dan Anda menyetelnya secara global, Anda harus mengatur ulang di akhir fungsi seperti:Jika tidak, setiap baris yang Anda lakukan nanti dalam skrip akan kacau.
EDIT 2 Untuk membagi pasangan nama / nilai atribut Anda dapat menambahkan
read_dom()
seperti:Kemudian tulis fungsi Anda untuk menguraikan dan mendapatkan data yang Anda inginkan seperti ini:
Kemudian saat Anda
read_dom
meneleponparse_dom
:Kemudian diberikan contoh markup berikut:
Anda harus mendapatkan hasil ini:
EDIT 3 pengguna lain mengatakan mereka mengalami masalah dengan itu di FreeBSD dan menyarankan menyimpan status keluar dari membaca dan mengembalikannya di akhir read_dom seperti:
Saya tidak melihat alasan mengapa itu tidak berhasil
sumber
IFS=\< read ...
saja:, yang hanya akan mengatur IFS untuk panggilan baca. (Perhatikan bahwa saya sama sekali tidak mendukung praktik penggunaanread
untuk mem-parsing xml, dan saya percaya melakukan hal itu penuh dengan bahaya dan harus dihindari.)Anda dapat melakukannya dengan sangat mudah hanya menggunakan bash. Anda hanya perlu menambahkan fungsi ini:
Sekarang Anda dapat menggunakan rdom seperti baca tetapi untuk dokumen html. Ketika dipanggil rdom akan menetapkan elemen ke variabel E dan konten ke var C.
Misalnya, untuk melakukan apa yang ingin Anda lakukan:
sumber
Alat baris perintah yang dapat dipanggil dari skrip shell meliputi:
Saya juga menggunakan xmllint dan xsltproc dengan sedikit skrip transformasi XSL untuk melakukan pemrosesan XML dari baris perintah atau dalam skrip shell.
sumber
Anda dapat menggunakan utilitas xpath. Itu diinstal dengan paket Perl XML-XPath.
Pemakaian:
atau XMLStarlet . Untuk menginstalnya di opensuse gunakan:
atau coba
cnf xml
di platform lain.sumber
xpath
yang sudah diinstal sebelumnya tidak cocok untuk digunakan sebagai komponen dalam skrip. Lihat misalnya stackoverflow.com/questions/15461737/… untuk penjelasan.apt-get install xmlstarlet
Ini cukup ...
sumber
apt-get install libxml-xpath-perl
.Lihat XML2 dari http://www.ofb.net/~egnor/xml2/ yang mengubah XML ke format berorientasi garis.
sumber
mulai dari jawaban chad, berikut ini adalah solusi kerja COMPLETE untuk mengurai UML, dengan penanganan komentar yang tepat, dengan hanya 2 fungsi kecil (lebih dari 2 bu Anda dapat mencampur semuanya). Saya tidak mengatakan chad tidak berfungsi sama sekali, tetapi memiliki terlalu banyak masalah dengan file XML yang diformat dengan buruk: Jadi Anda harus sedikit lebih rumit untuk menangani komentar dan spasi yang salah tempat / CR / TAB / dll.
Tujuan dari jawaban ini adalah untuk memberikan fungsi ready-2-use, out of the box untuk siapa saja yang membutuhkan parsing UML tanpa alat kompleks menggunakan perl, python atau apa pun. Bagi saya, saya tidak dapat menginstal cpan, atau modul perl untuk OS produksi lama yang saya kerjakan, dan python tidak tersedia.
Pertama, definisi kata-kata UML yang digunakan dalam posting ini:
EDIT: fungsi yang diperbarui, dengan pegangan:
Fungsinya, pertama adalah xml_read_dom yang disebut secara rekursif oleh xml_read:
dan yang kedua:
dan terakhir, fungsi rtrim, trim dan echo2 (to stderr):
Pewarnaan:
oh dan Anda akan memerlukan beberapa variabel dinamis pewarnaan rapi untuk didefinisikan pada awalnya, dan diekspor juga:
Cara memuat semua itu:
Entah Anda tahu cara membuat fungsi dan memuatnya melalui FPATH (ksh) atau emulasi FPATH (bash)
Jika tidak, cukup salin / tempel semua yang ada di baris perintah.
Bagaimana cara kerjanya:
Dengan mode Debug (-d) komentar dan atribut yang diuraikan dicetak ke stderr
sumber
./read_xml.sh: line 22: (-1): substring expression < 0
:?[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
Saya tidak mengetahui adanya alat parsing XML shell murni. Jadi Anda kemungkinan besar akan membutuhkan alat yang ditulis dalam bahasa lain.
Modul XML :: Twig Perl saya dilengkapi dengan alat seperti ini:, di
xml_grep
mana Anda mungkin akan menulis apa yang Anda inginkanxml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt
(-t
opsi memberi Anda hasilnya sebagai teks, bukan xml)sumber
Alat baris perintah lainnya adalah Xidel baru saya . Ini juga mendukung XPath 2 dan XQuery, bertentangan dengan xpath / xmlstarlet yang telah disebutkan.
Judulnya bisa dibaca seperti:
Dan itu juga memiliki fitur keren untuk mengekspor beberapa variabel ke bash. Sebagai contoh
set
$title
ke judul dan$imgcount
jumlah gambar dalam file, yang harus sefleksibel parsing langsung di bash.sumber
Nah, Anda bisa menggunakan utilitas xpath. Saya kira perl's XML :: Xpath mengandungnya.
sumber
Setelah beberapa penelitian untuk terjemahan antara Linux dan format Windows jalur file dalam file XML saya menemukan tutorial dan solusi menarik pada:
sumber
Walaupun ada beberapa utilitas konsol siap pakai yang mungkin melakukan apa yang Anda inginkan, mungkin akan memakan waktu lebih sedikit untuk menulis beberapa baris kode dalam bahasa pemrograman tujuan umum seperti Python yang dapat dengan mudah diperluas dan disesuaikan dengan kebutuhanmu.
Berikut ini adalah skrip python yang digunakan
lxml
untuk parsing - dibutuhkan nama file atau URL sebagai parameter pertama, ekspresi XPath sebagai parameter kedua, dan mencetak string / node yang cocok dengan ekspresi yang diberikan.Contoh 1
lxml
dapat diinstal denganpip install lxml
. Di ubuntu Anda bisa menggunakansudo apt install python-lxml
.Pemakaian
lxml
juga menerima URL sebagai input:Contoh 2
Skrip satu kali yang melayani tujuan sempit mengekstraksi nama modul dari file apache maven. Perhatikan bagaimana nama simpul (
module
) diawali dengan namespace default{http://maven.apache.org/POM/4.0.0}
:pom.xml :
module_extractor.py :
sumber
pip install
overapt-get
atauyum
panggilan ekstra . Terima kasih!Metode Yuzem dapat ditingkatkan dengan membalik urutan
<
dan>
tanda - tanda dalamrdom
fungsi dan tugas variabel, sehingga:menjadi:
Jika parsing tidak dilakukan seperti ini, tag terakhir dalam file XML tidak pernah tercapai. Ini bisa bermasalah jika Anda berniat untuk menghasilkan file XML lain di akhir
while
loop.sumber
Ini berfungsi jika Anda menginginkan atribut XML:
sumber
Meskipun sepertinya "tidak pernah menguraikan XML, JSON ... dari bash tanpa alat yang tepat" adalah saran yang bagus, saya tidak setuju. Jika ini adalah pekerjaan sampingan, itu adalah pinggang untuk mencari alat yang tepat, kemudian mempelajarinya ... Awk dapat melakukannya dalam hitungan menit. Program saya harus mengerjakan semua data yang disebutkan di atas dan lebih banyak lagi. Sial, saya tidak ingin menguji 30 alat untuk mem-parsing 5-7-10 format yang berbeda yang saya butuhkan jika saya dapat mengatasi masalah dalam hitungan menit. Saya tidak peduli dengan XML, JSON atau apa pun! Saya butuh solusi tunggal untuk semuanya.
Sebagai contoh: Program SmartHome saya mengelola rumah kami. Saat melakukannya, ia membaca sejumlah besar data dalam berbagai format berbeda yang tidak dapat saya kendalikan. Saya tidak pernah menggunakan alat khusus yang berdedikasi karena saya tidak ingin menghabiskan lebih dari beberapa menit untuk membaca data yang saya butuhkan. Dengan penyesuaian FS dan RS, solusi awk ini berfungsi sempurna untuk semua format teks. Tapi, itu mungkin bukan jawaban yang tepat ketika tugas utama Anda adalah bekerja terutama dengan banyak data dalam format itu!
Masalah parsing XML dari bash yang saya hadapi kemarin. Inilah cara saya melakukannya untuk format data hierarkis apa pun. Sebagai bonus - saya menetapkan data langsung ke variabel dalam skrip bash.
Agar lebih mudah dibaca, saya akan menyajikan solusi secara bertahap. Dari data tes OP, saya membuat file: test.xml
Parsing mengatakan XML dalam bash dan mengekstraksi data dalam 90 karakter:
Saya biasanya menggunakan versi yang lebih mudah dibaca karena lebih mudah untuk dimodifikasi dalam kehidupan nyata karena saya sering perlu menguji secara berbeda:
Saya tidak peduli bagaimana formatnya. Saya hanya mencari solusi paling sederhana. Dalam kasus khusus ini, saya dapat melihat dari data bahwa baris baru adalah pemisah rekaman (RS) dan bidang pembatas <> (FS). Dalam kasus asli saya, saya memiliki pengindeksan rumit dari 6 nilai dalam dua catatan, yang berkaitan dengan mereka, temukan ketika data ada ditambah bidang (catatan) mungkin atau mungkin tidak ada. Butuh 4 baris awk untuk menyelesaikan masalah dengan sempurna. Jadi, sesuaikan ide dengan setiap kebutuhan sebelum menggunakannya!
Bagian kedua hanya terlihat ada string yang diinginkan dalam garis (RS) dan jika demikian, mencetak bidang yang diperlukan (FS). Di atas butuh waktu sekitar 30 detik untuk menyalin dan beradaptasi dari perintah terakhir yang saya gunakan dengan cara ini (4 kali lebih lama). Dan itu dia! Dilakukan dalam 90 karakter.
Tapi, saya selalu perlu memasukkan data ke dalam variabel dalam skrip saya. Saya pertama kali menguji konstruksi seperti:
Dalam beberapa kasus saya menggunakan printf daripada print. Ketika saya melihat semuanya terlihat baik, saya hanya selesai menetapkan nilai ke variabel. Saya tahu banyak yang berpikir "eval" adalah "jahat", tidak perlu berkomentar :) Trik bekerja dengan baik pada keempat jaringan saya selama bertahun-tahun. Tetapi teruslah belajar jika Anda tidak mengerti mengapa ini bisa menjadi praktik yang buruk! Termasuk tugas variabel bash dan spasi yang cukup, solusi saya perlu 120 karakter untuk melakukan semuanya.
sumber