Apakah ada paket di luar sana, untuk Ubuntu dan / atau CentOS, yang memiliki alat baris perintah yang dapat menjalankan XPath one-liner seperti foo //element@attribute filename.xml
atau foo //element@attribute < filename.xml
dan mengembalikan hasil baris demi baris?
Saya mencari sesuatu yang akan memungkinkan saya untuk hanya apt-get install foo
atau yum install foo
dan kemudian hanya bekerja di luar kotak, tidak ada pembungkus atau adaptasi lain yang diperlukan.
Berikut adalah beberapa contoh hal yang mendekati:
Nokogiri. Jika saya menulis bungkus ini saya bisa memanggil bungkusnya dengan cara yang dijelaskan di atas:
#!/usr/bin/ruby
require 'nokogiri'
Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
puts row
end
XML :: XPath. Akan bekerja dengan bungkus ini:
#!/usr/bin/perl
use strict;
use warnings;
use XML::XPath;
my $root = XML::XPath->new(ioref => 'STDIN');
for my $node ($root->find($ARGV[0])->get_nodelist) {
print($node->getData, "\n");
}
xpath
dari XML :: XPath mengembalikan terlalu banyak noise, -- NODE --
dan attribute = "value"
.
xml_grep
dari XML :: Twig tidak dapat menangani ekspresi yang tidak mengembalikan elemen, jadi tidak dapat digunakan untuk mengekstrak nilai atribut tanpa diproses lebih lanjut.
EDIT:
echo cat //element/@attribute | xmllint --shell filename.xml
mengembalikan noise yang mirip dengan xpath
.
xmllint --xpath //element/@attribute filename.xml
kembali attribute = "value"
.
xmllint --xpath 'string(//element/@attribute)' filename.xml
mengembalikan apa yang saya inginkan, tetapi hanya untuk pertandingan pertama.
Untuk solusi lain yang hampir memuaskan pertanyaan, berikut adalah XSLT yang dapat digunakan untuk mengevaluasi ekspresi XPath yang berubah-ubah (memerlukan dyn: evaluasi dukungan dalam prosesor XSLT):
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:dyn="http://exslt.org/dynamic" extension-element-prefixes="dyn">
<xsl:output omit-xml-declaration="yes" indent="no" method="text"/>
<xsl:template match="/">
<xsl:for-each select="dyn:evaluate($pattern)">
<xsl:value-of select="dyn:evaluate($value)"/>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Jalankan dengan xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
.
sumber
xpath
berada pada STDERR dan bukan STDOUT.Jawaban:
Anda harus mencoba alat ini:
xmlstarlet
: dapat mengedit, memilih, mengubah ... Tidak diinstal secara default, xpath1xmllint
: sering diinstal secara default denganlibxml2-utils
, xpath1 (periksa pembungkus saya untuk--xpath
mengaktifkan rilis yang sangat lama dan keluaran terbatas baris baru (v <2.9.9)xpath
: diinstal melalui modul perlXML::XPath
, xpath1xml_grep
: diinstal melalui modul perlXML::Twig
, xpath1 (penggunaan xpath terbatas)xidel
: xpath3saxon-lint
: proyek saya sendiri, membungkus perpustakaan Java Saxon-HE @ Michael Michael, xpath3xmllint
dilengkapi denganlibxml2-utils
(dapat digunakan sebagai shell interaktif dengan--shell
sakelar)xmlstarlet
adalahxmlstarlet
.xpath
dilengkapi dengan modul perlXML::Xpath
xml_grep
dilengkapi dengan modul perlXML::Twig
xidel
adalahxidel
saxon-lint
menggunakan SaxonHE 9.6 , XPath 3.x (+ kompatibilitas retro)Mis:
.
sumber
xmlstarlet sel -T -t -m '//element/@attribute' -v '.' -n filename.xml
melakukan persis apa yang saya inginkan!xmllint
tidak mendukung argumen baris perintah--xpath
, tetapi sebagian besar tampaknya mendukung--shell
. Output kotor sedikit, tetapi masih berguna dalam ikatan.sel -t -m ... -v ...
contoh pertama dari halaman ini: arstechnica.com/information-technology/2005 / 11 / linux-20051115/2 , cocok dengan semua kecuali node terakhir dan menyimpan satu untuk ekspresi nilai seperti kasus penggunaan saya, saya masih tidak bisa mendapatkannya, saya hanya mendapatkan output kosong ..Anda juga dapat mencoba Xidel saya . Itu tidak ada dalam paket di repositori, tetapi Anda bisa mengunduhnya dari halaman web (tidak memiliki dependensi).
Ini memiliki sintaks sederhana untuk tugas ini:
Dan itu adalah salah satu alat yang langka yang mendukung XPath 2.
sumber
Satu paket yang sangat mungkin untuk diinstal pada sistem sudah adalah
python-lxml
. Jika demikian, ini dimungkinkan tanpa menginstal paket tambahan:sumber
stdin
. Itu menghilangkan kebutuhan untuk memasukkanopen()
danclose()
dalam one-liner yang sudah cukup panjang. Untuk mem-parsing file, jalankan sajapython -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))" < my_file.xml
dan biarkan shell Anda menangani pencarian file, membuka dan menutup.Dalam pencarian saya untuk meminta file maven pom.xml saya berlari di pertanyaan ini. Namun saya memiliki batasan berikut:
Saya telah mencoba banyak hal di atas tanpa hasil:
Solusi yang saya temui adalah stabil, pendek dan bekerja pada banyak platform dan yang matang adalah rexml lib builtin di ruby:
Apa yang mengilhami saya untuk menemukan yang ini adalah artikel-artikel berikut:
sumber
xmlstarlet
sebagai jawaban yang diterima, karena cocok dengan kriteria saya yang lebih luas dan sangat rapi . Tapi saya mungkin akan menggunakan solusi Anda dari waktu ke waktu.puts
bukannyap
dalam perintah Ruby.Saxon akan melakukan ini tidak hanya untuk XPath 2.0, tetapi juga untuk XQuery 1.0 dan (dalam versi komersial) 3.0. Itu tidak datang sebagai paket Linux, tetapi sebagai file jar. Sintaks (yang Anda dapat dengan mudah membungkus skrip sederhana) adalah
UPDATE 2020
Saxon 10.0 termasuk alat Gizmo, yang dapat digunakan secara interaktif atau dalam batch dari baris perintah. Sebagai contoh
sumber
libsaxonb-java
, tetapi jika saya menjalankansaxonb-xquery -qs://element/@attribute -s:filename.xml
saya mendapatkanSENR0001: Cannot serialize a free-standing attribute node
, masalah yang sama dengan misalnyaxml_grep
.-qs
seperti ini:'-qs:declare namespace mets="http://www.loc.gov/METS/";/mets:mets/mets:dmdSec'
Anda mungkin juga tertarik dengan xsh . Ini fitur mode interaktif di mana Anda dapat melakukan apa pun yang Anda suka dengan dokumen:
sumber
cpan XML::XSH2
.cpan XML::XSH2
gagal menginstal apa pun.jawaban clacke bagus tetapi saya pikir hanya berfungsi jika sumber Anda adalah XML yang dibentuk dengan baik, bukan HTML normal.
Jadi untuk melakukan hal yang sama untuk konten Web normal — dokumen HTML yang belum tentu XML terbentuk dengan baik:
Dan untuk menggunakan html5lib (untuk memastikan Anda mendapatkan perilaku parsing yang sama dengan browser Web — karena seperti parser browser, html5lib sesuai dengan persyaratan parsing dalam spesifikasi HTML).
sumber
Mirip dengan jawaban Mike dan clacke, ini adalah python one-liner (menggunakan python> = 2.5) untuk mendapatkan versi build dari file pom.xml yang mengelak dari fakta bahwa file pom.xml biasanya tidak memiliki dtd atau namespace default, jadi jangan muncul dengan baik untuk libxml:
Diuji pada Mac dan Linux, dan tidak memerlukan paket tambahan untuk diinstal.
sumber
lxml
atauxmllint
, atau bahkan Ruby. Dalam semangat format dalam jawaban saya sendiri , saya menulisnya sebagaipython3 -c "from xml.etree.ElementTree import parse; from sys import stdin; print(parse(stdin).find('.//element[subelement=\"value\"]/othersubelement').text)" <<< "$variable_containing_xml"
bash..getroot()
sepertinya tidak perlu.Selain XML :: XSH dan XML :: XSH2 ada beberapa
grep
utilitas seperti menyedot sebagaiApp::xml_grep2
danXML::Twig
(yang termasukxml_grep
daripadaxml_grep2
). Ini bisa sangat berguna ketika bekerja pada file XML besar atau banyak untuk oneliners atauMakefile
target cepat.XML::Twig
terutama baik untuk bekerja dengan untukperl
pendekatan scripting ketika Anda ingin sedikit aa lebih pengolahan dari Anda$SHELL
danxmllint
xstlproc
ditawarkan.Skema penomoran dalam nama aplikasi menunjukkan bahwa versi "2" adalah versi yang lebih baru / lebih baru dari alat yang sama yang mungkin memerlukan versi modul lain yang lebih baru (atau dari
perl
dirinya sendiri).sumber
xml_grep2 -t //element@attribute filename.xml
berfungsi dan melakukan apa yang saya harapkan (xml_grep --root //element@attribute --text_only filename.xml
masih belum, mengembalikan kesalahan "ekspresi tidak dikenal"). Bagus!xml_grep --pretty_print --root '//element[@attribute]' --text_only filename.xml
? Tidak yakin apa yang terjadi di sana atau apa yang dikatakan XPath[]
dalam kasus ini, tetapi mengelilingi@attribute
tanda kurung siku bekerja untukxml_grep
danxml_grep2
.//element/@attribute
, tidak//element@attribute
. Tampaknya tidak dapat mengeditnya, tetapi membiarkannya di sana daripada menghapus + ganti agar tidak membingungkan riwayat diskusi ini.//element[@attribute]
memilih elemen tipeelement
yang memiliki atributattribute
. Saya tidak ingin elemen, hanya atributnya.<element attribute='foo'/>
harus memberi sayafoo
, bukan yang penuh<element attribute='foo'/>
.--text_only
dalam konteks itu memberi saya string kosong dalam kasus elemen seperti<element attribute='foo'/>
tanpa simpul teks di dalamnya.Perlu disebutkan bahwa nokogiri sendiri dikirimkan dengan alat baris perintah, yang harus diinstal bersama
gem install nokogiri
.Anda mungkin menemukan posting blog ini bermanfaat .
sumber
Saya telah mencoba beberapa utilitas baris perintah XPath dan ketika saya menyadari saya menghabiskan terlalu banyak waktu untuk mencari dan mencari tahu bagaimana mereka bekerja, jadi saya menulis parser XPath yang paling sederhana dengan Python yang melakukan apa yang saya butuhkan.
Script di bawah ini menunjukkan nilai string jika ekspresi XPath mengevaluasi ke string, atau menunjukkan seluruh subnode XML jika hasilnya adalah simpul:
Menggunakan
lxml
- parser XML cepat yang ditulis dalam C yang tidak termasuk dalam pustaka python standar. Instal denganpip install lxml
. Di Linux / OSX mungkin perlu diawali dengansudo
.Pemakaian:
lxml juga dapat menerima URL sebagai input:
Ekstrak atribut url di bawah simpul enklosur yaitu
<enclosure url="http:...""..>)
:Xpath di Google Chrome
Sebagai catatan samping yang tidak terkait: Jika kebetulan Anda ingin menjalankan ekspresi XPath terhadap markup halaman web maka Anda dapat melakukannya langsung dari Chrome devtools: klik kanan halaman di Chrome> pilih Inspect, lalu di DevTools konsol tempelkan ekspresi XPath Anda sebagai
$x("//spam/eggs")
.Dapatkan semua penulis di halaman ini:
sumber
lxml
sudah disebutkan dalam dua jawaban lain bertahun-tahun sebelum Anda.Berikut ini satu use case xmlstarlet untuk mengekstrak data dari elemen bersarang elem1, elem2 ke satu baris teks dari tipe XML ini (juga menunjukkan cara menangani ruang nama):
Outputnya adalah
Dalam cuplikan ini, -m cocok dengan nilai atribut bersarang elem2, -v output (dengan ekspresi dan pengalamatan relatif), -o teks literal, -n menambahkan baris baru:
Jika diperlukan lebih banyak atribut dari elem1, seseorang dapat melakukannya seperti ini (juga memperlihatkan fungsi concat ()):
Perhatikan komplikasi (IMO yang tidak perlu) dengan ruang nama (ns, dideklarasikan dengan -N), yang membuat saya hampir menyerah pada xpath dan xmlstarlet, dan menulis konverter ad-hoc cepat.
sumber
Skrip Python saya xgrep.py melakukan persis ini. Untuk mencari semua atribut
attribute
elemenelement
dalam filefilename.xml ...
, Anda akan menjalankannya sebagai berikut:Ada berbagai sakelar untuk mengendalikan keluaran, seperti
-c
untuk menghitung kecocokan,-i
untuk indentasi bagian yang cocok, dan-l
untuk keluaran hanya nama file.Skrip tidak tersedia sebagai paket Debian atau Ubuntu, tetapi semua dependensinya adalah.
sumber
Karena proyek ini tampaknya cukup baru, periksa https://github.com/jeffbr13/xq , tampaknya menjadi pembungkus
lxml
, tetapi hanya itu yang Anda butuhkan (dan kirimkan solusi ad hoc menggunakan lxml dalam jawaban lain juga)sumber
Saya tidak senang dengan Python one-liners untuk permintaan HTML XPath, jadi saya menulis sendiri. Asumsikan bahwa Anda menginstal
python-lxml
paket atau berlaripip install --user lxml
:Setelah memilikinya, Anda dapat menggunakannya seperti dalam contoh ini:
sumber
Instal basis data BaseX , lalu gunakan "mode baris perintah mandiri" seperti ini:
basex -i - //element@attribute < filename.xml
atau
basex -i filename.xml //element@attribute
Bahasa query sebenarnya XQuery (3.0), bukan XPath, tetapi karena XQuery adalah superset dari XPath, Anda dapat menggunakan permintaan XPath tanpa pernah memperhatikan.
sumber