To naprawdę tylko wyjaśnienie odpowiedzi Yuzem , ale nie sądziłem, że tak wiele edycji powinno się robić komuś innemu, a komentarze nie pozwalają na formatowanie, więc ...
rdom (){local IFS=\> ; read -d \< E C ;}
Nazwijmy to „read_dom” zamiast „rdom”, oddzielmy to trochę i używaj dłuższych zmiennych:
OK, więc definiuje funkcję o nazwie read_dom. Pierwsza linia ustawia IFS (separator pól wejściowych) jako lokalny dla tej funkcji i zmienia go na>. Oznacza to, że kiedy czytasz dane, zamiast automatycznie dzielić je na spację, tabulację lub znaki nowej linii, są one dzielone na „>”. Następna linia mówi, że należy czytać dane wejściowe ze standardowego wejścia i zamiast zatrzymywać się na nowej linii, zatrzymaj się, gdy zobaczysz znak „<” (-d dla flagi separatora). To, co jest odczytywane, jest następnie dzielone za pomocą IFS i przypisywane do zmiennej ENTITY i CONTENT. Więc weź następujące:
<tag>value</tag>
Pierwsze wywołanie w celu read_domuzyskania pustego ciągu (ponieważ „<” jest pierwszym znakiem). To zostaje podzielone przez IFS na po prostu „”, ponieważ nie ma znaku „>”. Read następnie przypisuje pusty ciąg do obu zmiennych. Drugie wywołanie pobiera ciąg „tag> wartość”. To zostaje następnie podzielone przez IFS na dwa pola „tag” i „wartość”. Read następnie przypisuje zmienne, takie jak: ENTITY=tagi CONTENT=value. Trzecie wywołanie otrzymuje ciąg „/ tag>”. To zostaje podzielone przez IFS na dwa pola „/ tag” i „”. Read następnie przypisuje zmienne, takie jak: ENTITY=/tagi CONTENT=. Czwarte wywołanie zwróci stan niezerowy, ponieważ dotarliśmy do końca pliku.
Teraz jego pętla while została nieco wyczyszczona, aby pasowała do powyższego:
while read_dom;doif[[ $ENTITY ="title"]];then
echo $CONTENT
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
Pierwsza linia mówi po prostu, „podczas gdy funkcja read_dom zwraca stan zerowy, wykonaj następujące czynności”. Druga linia sprawdza, czy jednostka, którą właśnie widzieliśmy, to „tytuł”. W następnym wierszu zostanie wyświetlona treść tagu. Cztery linie wychodzą. Jeśli nie był to tytuł, pętla powtarza się w szóstym wierszu. Przekierowujemy „xhtmlfile.xhtml” na standardowe wejście (dla read_domfunkcji) i przekierowujemy standardowe wyjście do „titleOfXHTMLPage.txt” (echo z wcześniejszej części pętli).
Teraz biorąc pod uwagę następujące informacje (podobne do tego, co otrzymujesz z umieszczenia wiadra na S3) dla input.xml:
$ cat example.xml |./bash_xml.sh
bar type is: metal
foo size is:1789
EDIT 3 inny użytkownik powiedział, że ma z tym problemy we FreeBSD i zasugerował zapisanie statusu wyjścia z odczytu i zwrócenie go na końcu read_dom, na przykład:
Jeśli ustawisz IFS (separator pól wejściowych) jako globalny, powinieneś zresetować go z powrotem do jego pierwotnej wartości na końcu, zredagowałem odpowiedź, aby to mieć. W przeciwnym razie jakikolwiek inny podział danych wejściowych, który wykonasz później w skrypcie, będzie pomieszany. Podejrzewam, że powodem, dla którego lokalny nie działa, jest to, że albo używasz basha w trybie zgodności (jak twój shbang to #! / Bin / sh), albo jest to starożytna wersja bash.
czad
30
To, że możesz napisać własny parser, nie oznacza, że powinieneś.
Stephen Niedzielski
1
@chad to z pewnością mówi coś o przepływie pracy / implementacji AWS, że szukałem odpowiedzi na "bash xml", aby również pobrać zawartość wiadra S3!
Przypisywanie IFS do zmiennej lokalnej jest kruche i niepotrzebne. Po prostu zrób:, IFS=\< read ...co ustawi IFS tylko dla wywołania read. (Zauważ, że w żaden sposób nie popieram praktyki używania readdo parsowania xml i uważam, że jest to najeżone niebezpieczeństwem i powinno się go unikać.)
William Pursell
64
Możesz to zrobić bardzo łatwo używając samego basha. Musisz tylko dodać tę funkcję:
rdom (){local IFS=\> ; read -d \< E C ;}
Teraz możesz używać rdom jak read, ale dla dokumentów html. Po wywołaniu rdom przypisze element do zmiennej E, a zawartość do zmiennej C.
Na przykład, aby zrobić to, co chciałeś:
while rdom;doif[[ $E = title ]];then
echo $C
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
czy mógłbyś to rozwinąć? Założę się, że jest to dla ciebie zupełnie jasne ... i to może być świetna odpowiedź - gdybym mógł powiedzieć, co tam robisz ... czy możesz to trochę bardziej rozłożyć, być może generując jakieś próbki wyjściowe?
Alex Grey
1
Podziękowania dla oryginału - ten jednoliniowy jest tak cholernie elegancki i niesamowity.
Maverick
1
świetny hack, ale musiałem użyć podwójnych cudzysłowów, takich jak echo "$ C", aby zapobiec rozwijaniu powłoki i poprawnej interpretacji linii końcowych (zależy od kodowania)
user311174
8
Parsowanie XML za pomocą grep i awk nie jest w porządku . Może to być akceptowalny kompromis, jeśli XML jest wystarczająco prosty i nie masz za dużo czasu, ale nigdy nie można go nazwać dobrym rozwiązaniem.
peterh - Przywróć Monikę
59
Narzędzia wiersza polecenia, które można wywołać ze skryptów powłoki, obejmują:
4xpath - opakowanie wiersza poleceń wokół pakietu 4Suite Pythona
tak, drugie głosowanie / prośba - skąd pobrać te narzędzia, czy to znaczy, że trzeba ręcznie napisać opakowanie? Wolałbym nie tracić czasu na robienie tego, chyba że jest to konieczne.
David
4
sudo apt-get install libxml-xpath-perl
Andrew Wagner
22
Możesz użyć narzędzia xpath. Jest instalowany z pakietem Perl XML-XPath.
Stosowanie:
/usr/bin/xpath [filename] query
lub XMLStarlet . Aby zainstalować go na opensuse użyj:
Korzystanie z xml starlet jest zdecydowanie lepszą opcją niż pisanie własnego serializatora (jak sugerowano w innych odpowiedziach).
Bruno von Paris,
W wielu systemach xpathpreinstalowany element nie nadaje się do użycia jako składnik skryptów. Zobacz np. Stackoverflow.com/questions/15461737/… w celu uzyskania dalszych informacji.
zaczynając od odpowiedzi czada, oto KOMPLETNIE działające rozwiązanie do parsowania UML, z właściwą obsługą komentarzy, z zaledwie 2 małymi funkcjami (więcej niż 2, ale możesz je wszystkie mieszać). Nie mówię, że jeden z Chada w ogóle nie działał, ale miał zbyt wiele problemów ze źle sformatowanymi plikami XML: Więc musisz być nieco trudniejszy, aby radzić sobie z komentarzami i niewłaściwymi spacjami / CR / TAB / itp.
Celem tej odpowiedzi jest udostępnienie gotowych do użycia, gotowych do użycia funkcji bash każdemu, kto potrzebuje analizować UML bez skomplikowanych narzędzi przy użyciu perla, pythona lub czegokolwiek innego. Jeśli chodzi o mnie, nie mogę zainstalować modułów cpan ani perl dla starego produkcyjnego systemu operacyjnego, na którym pracuję, a Python nie jest dostępny.
Och, a będziesz potrzebować kilku zgrabnych, kolorujących zmiennych dynamicznych, które zostaną najpierw zdefiniowane i wyeksportowane:
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"'
Jak załadować to wszystko:
Albo wiesz, jak tworzyć funkcje i ładować je przez FPATH (ksh) lub emulację FPATH (bash)
Jeśli nie, po prostu skopiuj / wklej wszystko w wierszu poleceń.
Jak to działa:
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
W trybie debugowania (-d) komentarze i przeanalizowane atrybuty są wypisywane na stderr
Próbuję użyć dwóch powyższych funkcji, które dają następujące wyniki ./read_xml.sh: line 22: (-1): substring expression < 0:?
khmarbaise
Linia 22:[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
khmarbaise
przepraszam khmarbaise, to są funkcje powłoki bash. Jeśli chcesz zaadaptować je jako skrypty powłoki, z pewnością musisz spodziewać się drobnych dostosowań! Również zaktualizowane funkcje obsługują twoje błędy;)
scavenger
4
Nie znam żadnego narzędzia do analizowania czystego XML-a. Najprawdopodobniej będziesz potrzebować narzędzia napisanego w innym języku.
Mój moduł XML :: Twig Perl zawiera takie narzędzie:, xml_grepgdzie prawdopodobnie napiszesz to, co chcesz xml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt( -topcja daje wynik jako tekst zamiast xml)
Kolejnym narzędziem wiersza poleceń jest mój nowy Xidel . Obsługuje również XPath 2 i XQuery, w przeciwieństwie do wspomnianego już xpath / xmlstarlet.
Chociaż istnieje sporo gotowych narzędzi konsolowych, które mogą robić to, co chcesz, prawdopodobnie napisanie kilku wierszy kodu w języku programowania ogólnego przeznaczenia, takim jak Python, zajmie prawdopodobnie mniej czasu, który można łatwo rozszerzyć i dostosować do Twoje potrzeby.
Oto skrypt w Pythonie, który używa lxmldo analizy - przyjmuje nazwę pliku lub adres URL jako pierwszy parametr, wyrażenie XPath jako drugi parametr i drukuje ciągi / węzły pasujące do danego wyrażenia.
Przykład 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))
lxmlmożna zainstalować z pip install lxml. Na Ubuntu możesz użyć sudo apt install python-lxml.
Stosowanie
python xpath.py myfile.xml "//mynode"
lxml akceptuje również adres URL jako dane wejściowe:
Uwaga : Jeśli twój XML ma domyślną przestrzeń nazw bez prefiksu (np. xmlns=http://abc...), Musisz użyć pprzedrostka (dostarczonego przez 'hack') w swoich wyrażeniach, np. //p:moduleAby pobrać moduły z pom.xmlpliku. W przypadku, gdy pprefiks jest już odwzorowany w Twoim XML, musisz zmodyfikować skrypt, aby używał innego prefiksu.
Przykład 2
Jednorazowy skrypt, który służy wąskim celom wyodrębniania nazw modułów z pliku maven Apache. Zwróć uwagę, jak nazwa węzła ( module) jest poprzedzona domyślną przestrzenią nazw {http://maven.apache.org/POM/4.0.0}:
Jest to niesamowite, gdy chcesz uniknąć instalowania dodatkowych pakietów lub nie masz do nich dostępu. Na maszynie budowlanej, mogę usprawiedliwić dodatkowy pip installover apt-getlub yumpołączenia. Dzięki!
E. Moffat
0
Metodę Yuzema można ulepszyć odwracając kolejność znaków <i >w rdomfunkcji oraz przypisania zmiennych, tak aby:
rdom (){local IFS=\> ; read -d \< E C ;}
staje się:
rdom (){local IFS=\< ; read -d \> C E ;}
Jeśli parsowanie nie zostanie wykonane w ten sposób, ostatni znacznik w pliku XML nigdy nie zostanie osiągnięty. Może to być problematyczne, jeśli zamierzasz wyprowadzić inny plik XML na końcu whilepętli.
Chociaż wydaje się, że „nigdy nie parsuj XML, JSON… z basha bez odpowiedniego narzędzia” to rozsądna rada, nie zgadzam się. Jeśli to praca poboczna, warto poszukać odpowiedniego narzędzia, a potem się tego nauczyć ... Awk może to zrobić w kilka minut. Moje programy muszą pracować na wszystkich wyżej wymienionych i na wielu innych rodzajach danych. Do diabła, nie chcę testować 30 narzędzi do analizowania 5-7-10 różnych formatów, których potrzebuję, jeśli mogę rozwiązać problem w ciągu kilku minut. Nie obchodzi mnie XML, JSON czy cokolwiek! Potrzebuję jednego rozwiązania dla wszystkich.
Na przykład: mój program SmartHome obsługuje nasze domy. Robiąc to, czyta mnóstwo danych w zbyt wielu różnych formatach, których nie mogę kontrolować. Nigdy nie używam dedykowanych, odpowiednich narzędzi, ponieważ nie chcę spędzać więcej niż minuty na odczytywaniu potrzebnych mi danych. Dzięki dostosowaniom FS i RS to rozwiązanie awk działa doskonale dla każdego formatu tekstowego. Jednak może to nie być właściwa odpowiedź, gdy Twoim głównym zadaniem jest praca głównie z dużą ilością danych w tym formacie!
Problem z parsowaniem XML z bash napotkałem wczoraj. Oto jak to robię dla dowolnego hierarchicznego formatu danych. Jako bonus - przypisuję dane bezpośrednio do zmiennych w skrypcie basha.
Dla ułatwienia czytania przedstawię rozwiązanie etapami. Z danych testowych OP utworzyłem plik: test.xml
Przetwarzanie wspomnianego XML w bashu i wyodrębnianie danych w 90 znakach:
Nie obchodzi mnie, jak nazywa się ten format. Szukam tylko najprostszego rozwiązania. W tym konkretnym przypadku widzę z danych, że znak nowej linii jest separatorem rekordów (RS) i <> ogranicznikami pól (FS). W moim pierwotnym przypadku miałem skomplikowane indeksowanie 6 wartości w dwóch rekordach, odnosząc je, znajdując, kiedy dane istnieją oraz pola (rekordy) mogą istnieć lub nie. Idealne rozwiązanie problemu zajęło 4 linijki awk. Dlatego dostosuj pomysł do każdej potrzeby, zanim go użyjesz!
Druga część po prostu wygląda na to, że w linii (RS) jest poszukiwany łańcuch i jeśli tak, wypisuje potrzebne pola (FS). Powyższe zajęło mi około 30 sekund, aby skopiować i dostosować od ostatniego polecenia, którego użyłem w ten sposób (4 razy dłużej). I to jest to! Sporządzono w 90 znakach.
Ale zawsze muszę starannie umieścić dane w zmiennych w moim skrypcie. Najpierw testuję konstrukcje w następujący sposób:
W niektórych przypadkach używam printf zamiast print. Kiedy widzę, że wszystko wygląda dobrze, po prostu kończę przypisywanie wartości do zmiennych. Wiem, że wielu uważa, że „eval” jest „zły”, nie ma potrzeby komentowania :) Trick działa doskonale we wszystkich czterech moich sieciach od lat. Ale ucz się dalej, jeśli nie rozumiesz, dlaczego może to być zła praktyka! Uwzględniając przypisania zmiennych bash i duże odstępy, moje rozwiązanie potrzebuje 120 znaków, aby zrobić wszystko.
Odpowiedzi:
To naprawdę tylko wyjaśnienie odpowiedzi Yuzem , ale nie sądziłem, że tak wiele edycji powinno się robić komuś innemu, a komentarze nie pozwalają na formatowanie, więc ...
Nazwijmy to „read_dom” zamiast „rdom”, oddzielmy to trochę i używaj dłuższych zmiennych:
OK, więc definiuje funkcję o nazwie read_dom. Pierwsza linia ustawia IFS (separator pól wejściowych) jako lokalny dla tej funkcji i zmienia go na>. Oznacza to, że kiedy czytasz dane, zamiast automatycznie dzielić je na spację, tabulację lub znaki nowej linii, są one dzielone na „>”. Następna linia mówi, że należy czytać dane wejściowe ze standardowego wejścia i zamiast zatrzymywać się na nowej linii, zatrzymaj się, gdy zobaczysz znak „<” (-d dla flagi separatora). To, co jest odczytywane, jest następnie dzielone za pomocą IFS i przypisywane do zmiennej ENTITY i CONTENT. Więc weź następujące:
Pierwsze wywołanie w celu
read_dom
uzyskania pustego ciągu (ponieważ „<” jest pierwszym znakiem). To zostaje podzielone przez IFS na po prostu „”, ponieważ nie ma znaku „>”. Read następnie przypisuje pusty ciąg do obu zmiennych. Drugie wywołanie pobiera ciąg „tag> wartość”. To zostaje następnie podzielone przez IFS na dwa pola „tag” i „wartość”. Read następnie przypisuje zmienne, takie jak:ENTITY=tag
iCONTENT=value
. Trzecie wywołanie otrzymuje ciąg „/ tag>”. To zostaje podzielone przez IFS na dwa pola „/ tag” i „”. Read następnie przypisuje zmienne, takie jak:ENTITY=/tag
iCONTENT=
. Czwarte wywołanie zwróci stan niezerowy, ponieważ dotarliśmy do końca pliku.Teraz jego pętla while została nieco wyczyszczona, aby pasowała do powyższego:
Pierwsza linia mówi po prostu, „podczas gdy funkcja read_dom zwraca stan zerowy, wykonaj następujące czynności”. Druga linia sprawdza, czy jednostka, którą właśnie widzieliśmy, to „tytuł”. W następnym wierszu zostanie wyświetlona treść tagu. Cztery linie wychodzą. Jeśli nie był to tytuł, pętla powtarza się w szóstym wierszu. Przekierowujemy „xhtmlfile.xhtml” na standardowe wejście (dla
read_dom
funkcji) i przekierowujemy standardowe wyjście do „titleOfXHTMLPage.txt” (echo z wcześniejszej części pętli).Teraz biorąc pod uwagę następujące informacje (podobne do tego, co otrzymujesz z umieszczenia wiadra na S3) dla
input.xml
:i następującą pętlę:
Powinieneś wziąć:
Jeśli więc napisaliśmy
while
pętlę taką jak Yuzem:Otrzymalibyśmy listę wszystkich plików w zasobniku S3.
EDYCJA Jeśli z jakiegoś powodu
local IFS=\>
nie działa u Ciebie i ustawiasz ją globalnie, powinieneś zresetować ją na końcu funkcji, np .:W przeciwnym razie każdy podział linii, który wykonasz później w skrypcie, będzie pomieszany.
EDYCJA 2 Aby rozdzielić pary nazwa / wartość atrybutu, możesz rozszerzyć w ten
read_dom()
sposób:Następnie napisz swoją funkcję, aby przeanalizować i uzyskać dane, które chcesz w ten sposób:
Następnie podczas
read_dom
rozmowyparse_dom
:Następnie, biorąc pod uwagę następujący przykładowy znacznik:
Powinieneś otrzymać to wyjście:
EDIT 3 inny użytkownik powiedział, że ma z tym problemy we FreeBSD i zasugerował zapisanie statusu wyjścia z odczytu i zwrócenie go na końcu read_dom, na przykład:
Nie widzę powodu, dla którego to nie powinno działać
źródło
IFS=\< read ...
co ustawi IFS tylko dla wywołania read. (Zauważ, że w żaden sposób nie popieram praktyki używaniaread
do parsowania xml i uważam, że jest to najeżone niebezpieczeństwem i powinno się go unikać.)Możesz to zrobić bardzo łatwo używając samego basha. Musisz tylko dodać tę funkcję:
Teraz możesz używać rdom jak read, ale dla dokumentów html. Po wywołaniu rdom przypisze element do zmiennej E, a zawartość do zmiennej C.
Na przykład, aby zrobić to, co chciałeś:
źródło
Narzędzia wiersza polecenia, które można wywołać ze skryptów powłoki, obejmują:
Używam również xmllint i xsltproc z małymi skryptami transformacji XSL do przetwarzania XML z wiersza poleceń lub w skryptach powłoki.
źródło
Możesz użyć narzędzia xpath. Jest instalowany z pakietem Perl XML-XPath.
Stosowanie:
lub XMLStarlet . Aby zainstalować go na opensuse użyj:
lub wypróbuj
cnf xml
na innych platformach.źródło
xpath
preinstalowany element nie nadaje się do użycia jako składnik skryptów. Zobacz np. Stackoverflow.com/questions/15461737/… w celu uzyskania dalszych informacji.apt-get install xmlstarlet
To wystarczy ...
źródło
apt-get install libxml-xpath-perl
.Sprawdź XML2 z http://www.ofb.net/~egnor/xml2/, który konwertuje XML na format liniowy.
źródło
zaczynając od odpowiedzi czada, oto KOMPLETNIE działające rozwiązanie do parsowania UML, z właściwą obsługą komentarzy, z zaledwie 2 małymi funkcjami (więcej niż 2, ale możesz je wszystkie mieszać). Nie mówię, że jeden z Chada w ogóle nie działał, ale miał zbyt wiele problemów ze źle sformatowanymi plikami XML: Więc musisz być nieco trudniejszy, aby radzić sobie z komentarzami i niewłaściwymi spacjami / CR / TAB / itp.
Celem tej odpowiedzi jest udostępnienie gotowych do użycia, gotowych do użycia funkcji bash każdemu, kto potrzebuje analizować UML bez skomplikowanych narzędzi przy użyciu perla, pythona lub czegokolwiek innego. Jeśli chodzi o mnie, nie mogę zainstalować modułów cpan ani perl dla starego produkcyjnego systemu operacyjnego, na którym pracuję, a Python nie jest dostępny.
Najpierw definicja słów UML użytych w tym poście:
EDYCJA: zaktualizowane funkcje, z uchwytem:
Funkcje, pierwsza to xml_read_dom, który jest wywoływany rekurencyjnie przez xml_read:
a drugi:
i na koniec funkcje rtrim, trim i echo2 (to stderr):
Koloryzacja:
Och, a będziesz potrzebować kilku zgrabnych, kolorujących zmiennych dynamicznych, które zostaną najpierw zdefiniowane i wyeksportowane:
Jak załadować to wszystko:
Albo wiesz, jak tworzyć funkcje i ładować je przez FPATH (ksh) lub emulację FPATH (bash)
Jeśli nie, po prostu skopiuj / wklej wszystko w wierszu poleceń.
Jak to działa:
W trybie debugowania (-d) komentarze i przeanalizowane atrybuty są wypisywane na stderr
źródło
./read_xml.sh: line 22: (-1): substring expression < 0
:?[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
Nie znam żadnego narzędzia do analizowania czystego XML-a. Najprawdopodobniej będziesz potrzebować narzędzia napisanego w innym języku.
Mój moduł XML :: Twig Perl zawiera takie narzędzie:,
xml_grep
gdzie prawdopodobnie napiszesz to, co chceszxml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt
(-t
opcja daje wynik jako tekst zamiast xml)źródło
Kolejnym narzędziem wiersza poleceń jest mój nowy Xidel . Obsługuje również XPath 2 i XQuery, w przeciwieństwie do wspomnianego już xpath / xmlstarlet.
Tytuł można czytać tak:
Ma też fajną funkcję eksportowania wielu zmiennych do basha. Na przykład
ustawia
$title
tytuł i$imgcount
liczbę obrazów w pliku, co powinno być tak elastyczne, jak przetwarzanie go bezpośrednio w bashu.źródło
Cóż, możesz użyć narzędzia xpath. Wydaje mi się, że zawiera go XML :: Xpath Perla.
źródło
Po poszukiwaniach tłumaczenia między formatami Linux i Windows ścieżek plików w plikach XML znalazłem ciekawe samouczki i rozwiązania dotyczące:
źródło
Chociaż istnieje sporo gotowych narzędzi konsolowych, które mogą robić to, co chcesz, prawdopodobnie napisanie kilku wierszy kodu w języku programowania ogólnego przeznaczenia, takim jak Python, zajmie prawdopodobnie mniej czasu, który można łatwo rozszerzyć i dostosować do Twoje potrzeby.
Oto skrypt w Pythonie, który używa
lxml
do analizy - przyjmuje nazwę pliku lub adres URL jako pierwszy parametr, wyrażenie XPath jako drugi parametr i drukuje ciągi / węzły pasujące do danego wyrażenia.Przykład 1
lxml
można zainstalować zpip install lxml
. Na Ubuntu możesz użyćsudo apt install python-lxml
.Stosowanie
lxml
akceptuje również adres URL jako dane wejściowe:Przykład 2
Jednorazowy skrypt, który służy wąskim celom wyodrębniania nazw modułów z pliku maven Apache. Zwróć uwagę, jak nazwa węzła (
module
) jest poprzedzona domyślną przestrzenią nazw{http://maven.apache.org/POM/4.0.0}
:pom.xml :
module_extractor.py :
źródło
pip install
overapt-get
lubyum
połączenia. Dzięki!Metodę Yuzema można ulepszyć odwracając kolejność znaków
<
i>
wrdom
funkcji oraz przypisania zmiennych, tak aby:staje się:
Jeśli parsowanie nie zostanie wykonane w ten sposób, ostatni znacznik w pliku XML nigdy nie zostanie osiągnięty. Może to być problematyczne, jeśli zamierzasz wyprowadzić inny plik XML na końcu
while
pętli.źródło
Działa to, jeśli potrzebujesz atrybutów XML:
źródło
Chociaż wydaje się, że „nigdy nie parsuj XML, JSON… z basha bez odpowiedniego narzędzia” to rozsądna rada, nie zgadzam się. Jeśli to praca poboczna, warto poszukać odpowiedniego narzędzia, a potem się tego nauczyć ... Awk może to zrobić w kilka minut. Moje programy muszą pracować na wszystkich wyżej wymienionych i na wielu innych rodzajach danych. Do diabła, nie chcę testować 30 narzędzi do analizowania 5-7-10 różnych formatów, których potrzebuję, jeśli mogę rozwiązać problem w ciągu kilku minut. Nie obchodzi mnie XML, JSON czy cokolwiek! Potrzebuję jednego rozwiązania dla wszystkich.
Na przykład: mój program SmartHome obsługuje nasze domy. Robiąc to, czyta mnóstwo danych w zbyt wielu różnych formatach, których nie mogę kontrolować. Nigdy nie używam dedykowanych, odpowiednich narzędzi, ponieważ nie chcę spędzać więcej niż minuty na odczytywaniu potrzebnych mi danych. Dzięki dostosowaniom FS i RS to rozwiązanie awk działa doskonale dla każdego formatu tekstowego. Jednak może to nie być właściwa odpowiedź, gdy Twoim głównym zadaniem jest praca głównie z dużą ilością danych w tym formacie!
Problem z parsowaniem XML z bash napotkałem wczoraj. Oto jak to robię dla dowolnego hierarchicznego formatu danych. Jako bonus - przypisuję dane bezpośrednio do zmiennych w skrypcie basha.
Dla ułatwienia czytania przedstawię rozwiązanie etapami. Z danych testowych OP utworzyłem plik: test.xml
Przetwarzanie wspomnianego XML w bashu i wyodrębnianie danych w 90 znakach:
Zwykle używam bardziej czytelnej wersji, ponieważ łatwiej jest ją modyfikować w prawdziwym życiu, ponieważ często muszę testować inaczej:
Nie obchodzi mnie, jak nazywa się ten format. Szukam tylko najprostszego rozwiązania. W tym konkretnym przypadku widzę z danych, że znak nowej linii jest separatorem rekordów (RS) i <> ogranicznikami pól (FS). W moim pierwotnym przypadku miałem skomplikowane indeksowanie 6 wartości w dwóch rekordach, odnosząc je, znajdując, kiedy dane istnieją oraz pola (rekordy) mogą istnieć lub nie. Idealne rozwiązanie problemu zajęło 4 linijki awk. Dlatego dostosuj pomysł do każdej potrzeby, zanim go użyjesz!
Druga część po prostu wygląda na to, że w linii (RS) jest poszukiwany łańcuch i jeśli tak, wypisuje potrzebne pola (FS). Powyższe zajęło mi około 30 sekund, aby skopiować i dostosować od ostatniego polecenia, którego użyłem w ten sposób (4 razy dłużej). I to jest to! Sporządzono w 90 znakach.
Ale zawsze muszę starannie umieścić dane w zmiennych w moim skrypcie. Najpierw testuję konstrukcje w następujący sposób:
W niektórych przypadkach używam printf zamiast print. Kiedy widzę, że wszystko wygląda dobrze, po prostu kończę przypisywanie wartości do zmiennych. Wiem, że wielu uważa, że „eval” jest „zły”, nie ma potrzeby komentowania :) Trick działa doskonale we wszystkich czterech moich sieciach od lat. Ale ucz się dalej, jeśli nie rozumiesz, dlaczego może to być zła praktyka! Uwzględniając przypisania zmiennych bash i duże odstępy, moje rozwiązanie potrzebuje 120 znaków, aby zrobić wszystko.
źródło