Czy jest dostępny pakiet dla Ubuntu i / lub CentOS, który ma narzędzie wiersza poleceń, które może wykonywać jedno-liniowy XPath, taki jak foo //element@attribute filename.xml
lub, foo //element@attribute < filename.xml
i zwracać wyniki linia po linii?
Szukam czegoś, co pozwoliłoby mi tylko apt-get install foo
albo yum install foo
i po prostu działa out-of-the-box, bez opakowania lub inna adaptacja konieczne.
Oto kilka przykładów zbliżających się spraw:
Nokogiri. Jeśli napiszę to opakowanie, mógłbym wywołać opakowanie w sposób opisany powyżej:
#!/usr/bin/ruby
require 'nokogiri'
Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
puts row
end
XML :: XPath. Działa z tym opakowaniem:
#!/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
z XML :: XPath zwraca zbyt dużo hałasu, -- NODE --
a attribute = "value"
.
xml_grep
z XML :: Twig nie obsługuje wyrażeń, które nie zwracają elementów, dlatego nie można go użyć do wyodrębnienia wartości atrybutów bez dalszego przetwarzania.
EDYTOWAĆ:
echo cat //element/@attribute | xmllint --shell filename.xml
zwraca hałas podobny do xpath
.
xmllint --xpath //element/@attribute filename.xml
zwraca attribute = "value"
.
xmllint --xpath 'string(//element/@attribute)' filename.xml
zwraca to, czego chcę, ale tylko dla pierwszego meczu.
Dla innego rozwiązania, które prawie spełnia pytanie, oto XSLT, którego można użyć do oceny dowolnych wyrażeń XPath (wymaga obsługi dyn: Evaluation w procesorze 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>
Uruchom z xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
.
źródło
xpath
jest na STDERR, a nie na STDOUT.Odpowiedzi:
Powinieneś spróbować tych narzędzi:
xmlstarlet
: można edytować, wybierać, przekształcać ... Domyślnie nie jest instalowany, xpath1xmllint
: często instalowane domyślnie zlibxml2-utils
, xpath1 (sprawdź moje opakowanie, aby--xpath
włączyć bardzo stare wersje i znaki nowej linii rozdzielane (v <2.9.9)xpath
: zainstalowany przez moduł PerlaXML::XPath
, xpath1xml_grep
: zainstalowany przez moduł PerlaXML::Twig
, xpath1 (ograniczone użycie xpath)xidel
: xpath3saxon-lint
: mój własny projekt, opakowanie nad biblioteką Java Saxon-HE @ Michaela Kaya, xpath3xmllint
pochodzi zlibxml2-utils
(może być używany jako interaktywna powłoka z--shell
przełącznikiem)xmlstarlet
jestxmlstarlet
.xpath
pochodzi z modułem PerlaXML::Xpath
xml_grep
pochodzi z modułem PerlaXML::Twig
xidel
jestxidel
saxon-lint
używając SaxonHE 9.6 , XPath 3.x (+ kompatybilność retro)Np .:
.
źródło
xmlstarlet sel -T -t -m '//element/@attribute' -v '.' -n filename.xml
robi dokładnie to, czego chcę!xmllint
nie obsługują argumentu wiersza poleceń--xpath
, ale większość wydaje się wspierać--shell
. Nieznacznie brudniejsze wyjście, ale nadal przydatne w oprawie.sel -t -m ... -v ...
przykładem z tej strony: arstechnica.com/information-technology/2005 / 11 / linux-20051115/2 , dopasowując wszystkie oprócz ostatniego węzła i zapisując ten jeden dla wyrażenia wartości, takiego jak mój przypadek użycia, nadal nie mogę go uzyskać, po prostu otrzymuję puste dane wyjściowe ..Możesz także wypróbować mój Xidel . Nie ma go w pakiecie w repozytorium, ale można go po prostu pobrać ze strony internetowej (nie ma zależności).
Ma prostą składnię do tego zadania:
Jest to jedno z rzadkich narzędzi, które obsługują XPath 2.
źródło
Jest już jeden pakiet, który najprawdopodobniej zostanie zainstalowany w systemie
python-lxml
. Jeśli tak, jest to możliwe bez instalowania dodatkowego pakietu:źródło
stdin
. Eliminuje to potrzebę włączeniaopen()
iclose()
już dość długiej jedno-liniowej. Aby przeanalizować plik, po prostu uruchompython -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))" < my_file.xml
i pozwól powłoce obsługiwać wyszukiwanie, otwieranie i zamykanie pliku.W moich zapytaniach dotyczących plików maven pom.xml natknąłem się na to pytanie. Miałem jednak następujące ograniczenia:
Próbowałem wielu z powyższych bez powodzenia:
Rozwiązaniem, które natknąłem się na to, że jest stabilne, krótkie i działa na wielu platformach i jest dojrzałe, jest rexml lib wbudowany w Ruby:
Inspiracją do znalezienia tego były następujące artykuły:
źródło
xmlstarlet
jako przyjętą odpowiedź, ponieważ pasuje ona do moich szerszych kryteriów i jest naprawdę fajna . Ale prawdopodobnie od czasu do czasu będę używał twojego rozwiązania.puts
zamiastp
w poleceniu Ruby.Saxon zrobi to nie tylko dla XPath 2.0, ale także dla XQuery 1.0 i (w wersji komercyjnej) 3.0. Nie jest dostarczany jako pakiet Linux, ale jako plik jar. Składnia (którą można łatwo zawinąć w prosty skrypt) to
AKTUALIZACJA 2020
Saxon 10.0 zawiera narzędzie Gizmo, którego można używać interaktywnie lub wsadowo z wiersza poleceń. Na przykład
źródło
libsaxonb-java
ale jeśli uruchomięsaxonb-xquery -qs://element/@attribute -s:filename.xml
, dostajęSENR0001: Cannot serialize a free-standing attribute node
taki sam problem jak z npxml_grep
.-qs
następujący sposób:'-qs:declare namespace mets="http://www.loc.gov/METS/";/mets:mets/mets:dmdSec'
Możesz być także zainteresowany xsh . Posiada tryb interaktywny, w którym możesz robić co tylko chcesz z dokumentem:
źródło
cpan XML::XSH2
.cpan XML::XSH2
nic nie instaluje.Odpowiedź clacke jest świetna, ale myślę, że działa tylko wtedy, gdy źródłem jest dobrze sformatowany XML, a nie normalny HTML.
Aby zrobić to samo w przypadku normalnej zawartości sieci Web - dokumenty HTML, które niekoniecznie są dobrze sformatowanymi danymi XML:
I zamiast tego użyj html5lib (aby upewnić się, że otrzymujesz takie samo zachowanie podczas analizowania jak przeglądarki internetowe - ponieważ podobnie jak parsery przeglądarek, html5lib spełnia wymagania parsowania w specyfikacji HTML).
źródło
Podobnie do odpowiedzi Mike'a i Clacke'a, tutaj jest jedno-liniowy python (przy użyciu python> = 2.5), aby uzyskać wersję kompilacji z pliku pom.xml, który omija fakt, że pliki pom.xml zwykle nie mają dtd lub domyślna przestrzeń nazw, więc nie wydają się być poprawnie sformułowane w libxml:
Testowany na komputerach Mac i Linux i nie wymaga instalowania żadnych dodatkowych pakietów.
źródło
lxml
anixmllint
, ani nawet Ruby. W duchu formatu we własnej odpowiedzi napisałem go jakpython3 -c "from xml.etree.ElementTree import parse; from sys import stdin; print(parse(stdin).find('.//element[subelement=\"value\"]/othersubelement').text)" <<< "$variable_containing_xml"
w bash..getroot()
nie wydaje się konieczne.Oprócz XML :: XSH i XML :: XSH2 istnieją pewne
grep
podobne narzędzia ssące jakoApp::xml_grep2
iXML::Twig
(które zawierająxml_grep
raczej niżxml_grep2
). Mogą one być bardzo przydatne podczas pracy z dużymi lub licznymi plikami XML dla szybkich onelinerów lubMakefile
celów.XML::Twig
jest szczególnie miło pracować zperl
podejściem skryptowym, gdy chcesz nieco więcej przetwarzania niż twoje$SHELL
ixmllint
xstlproc
zaoferować.Schemat numerowania w nazwach aplikacji wskazuje, że wersje „2” są nowszą / późniejszą wersją zasadniczo tego samego narzędzia, które może wymagać późniejszych wersji innych modułów (lub
perl
samego).źródło
xml_grep2 -t //element@attribute filename.xml
działa i robi to, czego oczekuję (xml_grep --root //element@attribute --text_only filename.xml
wciąż nie, zwraca błąd „nierozpoznane wyrażenie”). Wspaniały!xml_grep --pretty_print --root '//element[@attribute]' --text_only filename.xml
? Nie jestem pewien, co się tam dzieje ani o czym mówi XPath[]
w tym przypadku, ale otaczanie@attribute
nawiasami kwadratowymi działa dlaxml_grep
ixml_grep2
.//element/@attribute
nie//element@attribute
. Najwyraźniej nie można go edytować, ale pozostawiając go tam zamiast usuwać + zamieniać, aby nie pomylić historii tej dyskusji.//element[@attribute]
wybiera elementy typu,element
które mają atrybutattribute
. Nie chcę elementu, tylko atrybut.<element attribute='foo'/>
powinien mi daćfoo
, a nie pełny<element attribute='foo'/>
.--text_only
w tym kontekście daje mi pusty ciąg w przypadku elementu takiego jak<element attribute='foo'/>
bez węzła tekstowego w środku.Należy wspomnieć, że sam nokogiri jest dostarczany z narzędziem wiersza poleceń, które należy zainstalować
gem install nokogiri
.Można znaleźć tego blogu użyteczne .
źródło
Wypróbowałem kilka narzędzi XPath z wiersza poleceń i kiedy zdałem sobie sprawę, że spędzam zbyt dużo czasu na wyszukiwaniu i zastanawianiu się, jak one działają, napisałem więc najprostszy możliwy parser XPath w Pythonie, który zrobił to, czego potrzebowałem.
Poniższy skrypt pokazuje wartość ciągu, jeśli wyrażenie XPath przekształca się w ciąg, lub pokazuje cały podwęzeł XML, jeśli wynikiem jest węzeł:
Wykorzystuje
lxml
- szybki parser XML napisany w C, który nie jest zawarty w standardowej bibliotece Pythona. Zainstaluj za pomocąpip install lxml
. W systemie Linux / OSX może wymagać prefiksusudo
.Stosowanie:
lxml może również akceptować adres URL jako dane wejściowe:
Wyodrębnij atrybut url w węźle obudowy, tj .
<enclosure url="http:...""..>)
:Xpath w Google Chrome
Jako niepowiązana uwaga dodatkowa: jeśli przypadkiem chcesz uruchomić wyrażenie XPath wobec znaczników strony internetowej, możesz to zrobić bezpośrednio z narzędzi devtools Chrome: kliknij prawym przyciskiem myszy stronę w Chrome> wybierz Sprawdź, a następnie w DevTools konsola wklej wyrażenie XPath jako
$x("//spam/eggs")
.Pobierz wszystkich autorów na tej stronie:
źródło
lxml
już wspomniano w dwóch innych odpowiedziach lat zanim same.Oto jeden przypadek użycia xmlstarlet do wyodrębnienia danych z elementów zagnieżdżonych elem1, elem2 do jednego wiersza tekstu z tego typu XML (pokazujący również, jak obsługiwać przestrzenie nazw):
Wyjście będzie
W tym fragmencie -m dopasowuje zagnieżdżony elem2, -v wyświetla wartości atrybutów (z wyrażeniami i względnym adresowaniem), -o dosłowny tekst, -n dodaje nowy wiersz:
Jeśli potrzeba więcej atrybutów z elem1, można to zrobić w następujący sposób (pokazując również funkcję concat ()):
Zwróć uwagę na (niepotrzebne IMO) komplikacje z przestrzeniami nazw (ns, zadeklarowane z -N), które prawie mnie poddały na xpath i xmlstarlet, i napisałem szybki konwerter ad-hoc.
źródło
Mój skrypt xgrep.py w Pythonie właśnie to robi. Aby wyszukać wszystkie atrybuty
attribute
elementówelement
w plikachfilename.xml ...
, uruchom go w następujący sposób:Istnieją różne przełączniki do sterowania danymi wyjściowymi, na przykład
-c
do zliczania dopasowań,-i
do wcięcia pasujących części i-l
do wysyłania tylko nazw plików.Skrypt nie jest dostępny jako pakiet Debian lub Ubuntu, ale wszystkie jego zależności są.
źródło
Ponieważ ten projekt jest pozornie nowy, sprawdź https://github.com/jeffbr13/xq , wydaje się to być otoczeniem
lxml
, ale to wszystko, czego naprawdę potrzebujesz (i opublikowałem rozwiązania ad hoc przy użyciu lxml również w innych odpowiedziach)źródło
Nie byłem zadowolony z jedno-liniowych zapytań Python do zapytań HTML XPath, więc napisałem własny. Zakłada, że zainstalowałeś
python-lxml
pakiet lub uruchomiłeśpip install --user lxml
:Gdy go masz, możesz użyć go tak jak w tym przykładzie:
źródło
Zainstaluj bazę danych BaseX , a następnie użyj „samodzielnego trybu wiersza polecenia” w następujący sposób:
basex -i - //element@attribute < filename.xml
lub
basex -i filename.xml //element@attribute
Językiem zapytań jest w rzeczywistości XQuery (3.0), a nie XPath, ale ponieważ XQuery jest nadzbiorem XPath, można używać zapytań XPath bez uprzedzenia.
źródło