Saya memiliki file log di host unix (cukup besar> 500 MB) setiap hari dengan XML yang dicetak di sana yang dikirim ke sistem lain.

Struktur XML kemungkinan seperti berikut:

2021-01-04 08:44:43,174 Not related message
2021-01-04 08:45:45,174 [Sender] INFO  com....router.MessageRouter - Publishing Message: <?xml version="1.0" encoding="UTF-8"?>
  <Q1:book>
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
    <id>6AA2BC</id>
    <metadata>
       <isbn>123-432-234</isbn>
       <catalogId>111</catalogId>
    </metadata>
    <relatedBook>
       <metabook id="3AA345">Everyday Italian. Part 2</metabook>
       <metabook id="7ANNN2">Everyday Italian. Part 3</metabook>
    </relatedBook>
  </Q1:book>
2021-01-04 08:46:23,174 Not related message
2021-01-04 08:46:51,174 Not related message
2021-01-04 08:47:21,174 Not related message
2021-01-04 08:49:45,174 Message: <?xml version="1.0" encoding="UTF-8"?>
  <Q1:book>
    <title lang="en">Everyday Italian. Part 2</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
    <id>3AA345</id>
    <metadata>
       <isbn>123-432-235</isbn>
       <catalogId>115</catalogId>
    </metadata>
    <relatedBook>
       <metabook id="6AA2BC">Everyday Italian. Part 2</metabook>
       <metabook id="7ANNN2">Everyday Italian. Part 3</metabook>
    </relatedBook>
  </Q1:book>

Dan ada lusinan XML dalam log seperti itu.

Saya memiliki id dari xml yang saya inginkan (mis. 6AA2BC) dan saya perlu mengekstrak XML lengkap yang terkait dengannya menggunakan perintah Linux.

Jika saya melakukan sesuatu seperti grep 6AA2BC file.log Saya akan menerima satu-satunya baris <id>3AA345</id>

Saya telah mencoba berbagai pendekatan yang dijelaskan oleh komunitas dan bisa mendapatkan SEMUA XML menggunakan

grep -Poz '(?<=<Q1:book)(.*?\n)*?.*?(?=</Q1:book>)' file.log tetapi jika saya menambahkan id ke permintaan, itu tidak berfungsi

Output yang diharapkan: XML penuh dengan id tertentu = 6AA2BC

<Q1:book>
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
    <id>6AA2BC</id>
    <metadata>
       <isbn>123-432-234</isbn>
       <catalogId>111</catalogId>
    </metadata>
    <relatedBook>
       <metabook id="3AA345">Everyday Italian. Part 2</metabook>
       <metabook id="7ANNN2">Everyday Italian. Part 3</metabook>
    </relatedBook>
  </Q1:book>

Adakah yang bisa, tolong, jelaskan apa cara terbaik untuk melakukan ini?

2
Nick 4 Januari 2021, 17:17

3 jawaban

Jawaban Terbaik

Pengurai xml yang tepat seperti xmlstarlet atau xmllint adalah solusi terbaik untuk XML tetapi mengingat tidak ada teks xml dalam file, awk adalah alternatifnya:

awk 'BEGIN { RS="(</Q1:book>)|(<Q1>)" } /<id>6AA2BC<\/id>/ { print "<Q1>";print $0;print "</Q1:book>" }' file

Setel pemisah catatan ke "" atau "" dan cetak catatan bersama dengan tag Q1 awal dan akhir ketika id sama dengan 6AA2BC

0
Raman Sailopal 4 Januari 2021, 15:34

Satu lagi diuji dengan GNU awk

awk '/<Q1/{f=1}f{i = i $0 ORS }/<\/Q1/{if(i~/<id>6AA2BC/){printf "%s", i} i=f="" }' file.log
2
Thomas Hansen 4 Januari 2021, 19:49

Misalkan Anda telah menginstal skrip Perl xpath di sistem Linux Anda, Anda dapat melakukan hal berikut:

Untuk mengekstrak simpul Q1:book yang memiliki string teks 6AA2BC di subnode id dari input Anda di atas, Anda dapat menggunakan:

/usr/bin/xpath -q -e '//Q1:book[id/text()="6AA2BC"]' file.log

Tapi... pertama, Anda harus membersihkan input Anda, dan menambahkan tag pembuka root di awal dan tag penutup yang sesuai di akhir.

Saat baris XML dimulai dengan spasi, dan baris lainnya tanpa spasi, pertahankan baris XML menggunakan filter:

sed '/^[^ ]/d'

Tambahkan tag root pembuka yang juga harus menyertakan definisi ruang nama Q1 agar dapat bekerja dengan perintah menggunakan pilihan XPATH:

echo '<?xml version="1.0" encoding="UTF-8"?>'
echo '<root xmlns:Q1="https://example.com/mynamespace">'

Pada awalnya, dan:

echo "</root>"

Pada akhirnya.

Menggabungkan elemen-elemen di atas memberi kita liner berikutnya di Linux, yang akan saya bagi menjadi beberapa baris demi kejelasan

( echo '<?xml version="1.0" encoding="UTF-8"?>'
  echo '<root xmlns:Q1="https://example.com/mynamespace">'
  cat file.log | sed '/^[^ ]/d'
  echo "</root>"
) | /usr/bin/xpath -q -e '//Q1:book[id/text()="6AA2BC"]'

Jika Anda memiliki xmllint di sistem Anda alih-alih xpath, cukup terbitkan:

| /usr/bin/xmllint --xpath '//*[local-name()="book" and id/text()="6AA2BC"]' -

Sebagai bagian terakhir dari perintah.

1
Pierre François 5 Januari 2021, 14:40