Dies ist wirklich nur eine Erklärung von Yuzems Antwort, aber ich hatte nicht das Gefühl, dass so viel an jemand anderem bearbeitet werden sollte, und Kommentare erlauben keine Formatierung, also ...
rdom (){local IFS=\> ; read -d \< E C ;}
Nennen wir das "read_dom" anstelle von "rdom", platzieren Sie es ein wenig und verwenden Sie längere Variablen:
Okay, es definiert eine Funktion namens read_dom. In der ersten Zeile wird IFS (das Eingabefeldtrennzeichen) für diese Funktion lokalisiert und in> geändert. Das heißt, wenn Sie Daten lesen, anstatt sie automatisch auf Leerzeichen, Tabulatoren oder Zeilenumbrüche aufzuteilen, werden sie auf '>' aufgeteilt. In der nächsten Zeile wird angegeben, dass Eingaben von stdin gelesen werden sollen. Anstatt an einer neuen Zeile anzuhalten, halten Sie an, wenn Sie ein '<' (das -d für Deliminator-Flag) sehen. Was gelesen wird, wird dann mit dem IFS aufgeteilt und der Variablen ENTITY und CONTENT zugewiesen. Nehmen Sie also Folgendes:
<tag>value</tag>
Der erste Aufruf, read_domum eine leere Zeichenfolge zu erhalten (da das '<' das erste Zeichen ist). Das wird von IFS in nur '' aufgeteilt, da es kein '>' Zeichen gibt. Read weist dann beiden Variablen eine leere Zeichenfolge zu. Der zweite Aufruf erhält die Zeichenfolge 'tag> value'. Das wird dann vom IFS in die beiden Felder 'tag' und 'value' aufgeteilt. Read weist dann die Variablen wie folgt zu: ENTITY=tagund CONTENT=value. Der dritte Aufruf erhält die Zeichenfolge '/ tag>'. Das wird vom IFS in die beiden Felder '/ tag' und '' aufgeteilt. Read weist dann die Variablen wie folgt zu: ENTITY=/tagund CONTENT=. Der vierte Aufruf gibt einen Status ungleich Null zurück, da das Dateiende erreicht ist.
Jetzt hat seine while-Schleife ein wenig aufgeräumt, um dem oben genannten zu entsprechen:
while read_dom;doif[[ $ENTITY ="title"]];then
echo $CONTENT
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
In der ersten Zeile steht nur: "Während die Funktion read_dom den Status Null zurückgibt, gehen Sie wie folgt vor." In der zweiten Zeile wird überprüft, ob die Entität, die wir gerade gesehen haben, "Titel" ist. In der nächsten Zeile wird der Inhalt des Tags wiedergegeben. Die vier Zeilen werden beendet. Wenn es nicht die Titelentität war, wird die Schleife in der sechsten Zeile wiederholt. Wir leiten "xhtmlfile.xhtml" in die Standardeingabe (für die read_domFunktion) und die Standardausgabe in "titleOfXHTMLPage.txt" (das Echo von früher in der Schleife) um.
Geben Sie nun Folgendes an (ähnlich wie beim Auflisten eines Buckets in S3) für input.xml:
Wenn wir also eine whileSchleife wie die von Yuzem geschrieben haben:
while read_dom;doif[[ $ENTITY ="Key"]];then
echo $CONTENT
fidone< input.xml
Wir würden eine Liste aller Dateien im S3-Bucket erhalten.
BEARBEITEN
Wenn es aus irgendeinem Grund local IFS=\>bei Ihnen nicht funktioniert und Sie es global festlegen, sollten Sie es am Ende der Funktion wie folgt zurücksetzen:
$ cat example.xml |./bash_xml.sh
bar type is: metal
foo size is:1789
EDIT 3 Ein anderer Benutzer gab an, Probleme mit FreeBSD zu haben, und schlug vor, den Exit-Status vor dem Lesen zu speichern und am Ende von read_dom zurückzugeben.
Wenn Sie IFS (das Eingabefeldtrennzeichen) global machen, sollten Sie es am Ende auf seinen ursprünglichen Wert zurücksetzen. Ich habe die Antwort bearbeitet, um dies zu haben. Andernfalls wird jede andere Eingabeaufteilung, die Sie später in Ihrem Skript vornehmen, durcheinander gebracht. Ich vermute, der Grund, warum local für Sie nicht funktioniert, ist, dass Sie entweder bash in einem Kompatibilitätsmodus verwenden (wie Ihr shbang #! / Bin / sh ist) oder es ist eine alte Version von bash.
Chad
30
Nur weil Sie Ihren eigenen Parser schreiben können, heißt das nicht, dass Sie es sollten.
Stephen Niedzielski
1
@chad es sicherlich etwas sagt über AWS‘Workflow / Implementierung , dass ich nach einer Antwort auf‚bash xml‘war auf der Suche auch wget den Inhalt eines S3 Eimer!
Alastair
2
@Alastair siehe github.com/chad3814/s3scripts für eine Reihe von Bash-Skripten, die wir verwenden, um S3-Objekte zu manipulieren
chad
5
Das Zuweisen von IFS in einer lokalen Variablen ist fragil und nicht erforderlich. Tun Sie einfach : IFS=\< read ..., wodurch nur IFS für den Leseaufruf festgelegt wird. (Beachten Sie, dass ich die Praxis des readParsen von XML in keiner Weise befürworte , und ich glaube, dass dies mit Gefahren behaftet ist und vermieden werden sollte.)
William Pursell
64
Sie können dies sehr einfach mit nur Bash tun. Sie müssen nur diese Funktion hinzufügen:
rdom (){local IFS=\> ; read -d \< E C ;}
Jetzt können Sie rdom wie read verwenden, aber für HTML-Dokumente. Beim Aufruf von rdom wird das Element der Variablen E und der Inhalt der Variable C zugewiesen.
Zum Beispiel, um das zu tun, was Sie tun wollten:
while rdom;doif[[ $E = title ]];then
echo $C
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
Könnten Sie das näher erläutern? Ich würde wetten, dass es Ihnen vollkommen klar ist. Und dies könnte eine großartige Antwort sein. Wenn ich sagen könnte, was Sie dort gemacht haben. Können Sie es ein wenig weiter aufschlüsseln und möglicherweise eine Beispielausgabe generieren?
Alex Gray
1
Dank des Originals - dieser Einzeiler ist so verdammt elegant und erstaunlich.
Außenseiter
1
Toller Hack, aber ich musste doppelte Anführungszeichen wie Echo "$ C" verwenden, um die Shell-Erweiterung und die korrekte Interpretation der Endzeilen zu verhindern (abhängig von der Folge)
user311174
8
Das Parsen von XML mit grep und awk ist nicht in Ordnung . Es kann ein akzeptabler Kompromiss sein, wenn die XMLs einfach genug sind und Sie nicht zu viel Zeit haben, aber es kann nie als gute Lösung bezeichnet werden.
Peter
59
Zu den Befehlszeilentools, die über Shell-Skripte aufgerufen werden können, gehören:
4xpath - Befehlszeilen-Wrapper um das 4Suite- Paket von Python
xpath - Befehlszeilen-Wrapper um Perls XPath-Bibliothek
Xidel - Funktioniert sowohl mit URLs als auch mit Dateien. Funktioniert auch mit JSON
Ich verwende auch xmllint und xsltproc mit kleinen XSL-Transformationsskripten, um die XML-Verarbeitung über die Befehlszeile oder in Shell-Skripten durchzuführen.
Ja, eine zweite Abstimmung / Anfrage - wo kann man diese Tools herunterladen, oder meinst du, man muss manuell einen Wrapper schreiben? Ich würde lieber keine Zeit damit verschwenden, es sei denn, dies ist notwendig.
David
4
sudo apt-get install libxml-xpath-perl
Andrew Wagner
22
Sie können das Dienstprogramm xpath verwenden. Es wird mit dem Perl XML-XPath-Paket installiert.
Verwendung:
/usr/bin/xpath [filename] query
oder XMLStarlet . Um es auf opensuse zu installieren, verwenden Sie:
sudo zypper install xmlstarlet
oder versuchen Sie es cnf xmlauf anderen Plattformen.
Die Verwendung von XML-Starlet ist definitiv eine bessere Option als das Schreiben eines eigenen Serializers (wie in den anderen Antworten vorgeschlagen).
Bruno von Paris
Auf vielen Systemen ist die xpathvorinstallierte Version nicht für die Verwendung als Komponente in Skripten geeignet. Siehe z. B. stackoverflow.com/questions/15461737/… für eine Ausarbeitung.
Ausgehend von der Antwort des Chad ist hier die KOMPLETTE Arbeitslösung zum Parsen von UML mit korrekter Behandlung von Kommentaren mit nur 2 kleinen Funktionen (mehr als 2 bu können Sie alle mischen). Ich sage nicht, dass chads überhaupt nicht funktioniert hat, aber es gab zu viele Probleme mit schlecht formatierten XML-Dateien: Sie müssen also etwas kniffliger sein, um mit Kommentaren und falsch platzierten Leerzeichen / CR / TAB / etc. Zu umgehen.
Der Zweck dieser Antwort besteht darin, jedem, der UML ohne komplexe Tools mit Perl, Python oder etwas anderem analysieren muss, sofort einsatzbereite Bash-Funktionen zur Verfügung zu stellen. Ich kann weder cpan noch Perl-Module für das alte Produktionsbetriebssystem installieren, an dem ich arbeite, und Python ist nicht verfügbar.
Zunächst eine Definition der in diesem Beitrag verwendeten UML-Wörter:
Oh, und Sie müssen zunächst einige ordentliche kolorierende dynamische Variablen definieren und auch exportieren:
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"'
Wie man all das Zeug lädt:
Entweder wissen Sie, wie Sie Funktionen erstellen und über FPATH (ksh) oder eine Emulation von FPATH (bash) laden.
Wenn nicht, kopieren Sie einfach alles in die Befehlszeile.
Wie funktioniert es:
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
Im Debug-Modus (-d) werden Kommentare und analysierte Attribute auf stderr gedruckt
sorry khmarbaise, das sind bash shell funktionen. Wenn Sie sie als Shell-Skripte anpassen möchten, müssen Sie mit einigen geringfügigen Anpassungen rechnen! Auch die aktualisierten Funktionen behandeln Ihre Fehler;)
Scavenger
4
Mir ist kein reines Shell-XML-Parsing-Tool bekannt. Sie benötigen also höchstwahrscheinlich ein Tool, das in einer anderen Sprache geschrieben ist.
Mein XML :: Twig Perl-Modul enthält ein solches Tool: xml_grepHier können Sie wahrscheinlich schreiben, als was Sie möchten xml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt(die -tOption gibt Ihnen das Ergebnis als Text anstelle von XML).
Ein weiteres Kommandozeilen-Tool ist mein neues Xidel . Es unterstützt auch XPath 2 und XQuery, im Gegensatz zu dem bereits erwähnten xpath / xmlstarlet.
Nach einigen Recherchen zur Übersetzung der Dateipfade in XML-Dateien zwischen Linux- und Windows-Formaten fand ich interessante Tutorials und Lösungen zu folgenden Themen:
Zwar gibt es einige vorgefertigte Konsolendienstprogramme, die möglicherweise das tun, was Sie möchten, aber es wird wahrscheinlich weniger Zeit in Anspruch nehmen, einige Codezeilen in einer universellen Programmiersprache wie Python zu schreiben, die Sie problemlos erweitern und anpassen können Deine Bedürfnisse.
Hier ist ein Python-Skript, das lxmlzum Parsen verwendet wird: Es verwendet den Namen einer Datei oder einer URL als ersten Parameter, einen XPath-Ausdruck als zweiten Parameter und druckt die Zeichenfolgen / Knoten, die dem angegebenen Ausdruck entsprechen.
Beispiel 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))
lxmlkann mit installiert werden pip install lxml. Auf Ubuntu können Sie verwenden sudo apt install python-lxml.
Hinweis : Wenn Ihr XML einen Standard-Namespace ohne Präfix hat (z. B. xmlns=http://abc...), müssen Sie das pPräfix (bereitgestellt durch den 'Hack') in Ihren Ausdrücken verwenden, z. B. //p:moduleum die Module aus einer pom.xmlDatei abzurufen. Falls das pPräfix bereits in Ihrem XML zugeordnet ist, müssen Sie das Skript ändern, um ein anderes Präfix zu verwenden.
Beispiel 2
Ein einmaliges Skript, das dem engen Zweck dient, Modulnamen aus einer Apache-Maven-Datei zu extrahieren. Beachten Sie, wie dem Knotennamen ( module) der Standard-Namespace vorangestellt wird {http://maven.apache.org/POM/4.0.0}:
Dies ist fantastisch, wenn Sie entweder die Installation zusätzlicher Pakete vermeiden möchten oder keinen Zugriff darauf haben. Auf einer Build-Maschine kann ich ein zusätzliches pip installOver apt-getoder einen yumCall rechtfertigen . Vielen Dank!
E. Moffat
0
Die Methode von Yuzem kann verbessert werden, indem die Reihenfolge der <und >-Zeichen in der rdomFunktion und die Variablenzuweisungen umgekehrt werden , so dass:
rdom (){local IFS=\> ; read -d \< E C ;}
wird:
rdom (){local IFS=\< ; read -d \> C E ;}
Wenn das Parsen nicht so durchgeführt wird, wird das letzte Tag in der XML-Datei nie erreicht. Dies kann problematisch sein, wenn Sie am Ende der whileSchleife eine weitere XML-Datei ausgeben möchten.
Obwohl es so aussieht, als ob "niemals XML, JSON ... von Bash ohne ein geeignetes Tool analysieren" ein guter Rat ist, bin ich anderer Meinung. Wenn dies ein Nebenjob ist, ist es schwierig, nach dem richtigen Werkzeug zu suchen und es dann zu lernen ... Awk kann es in Minuten erledigen. Meine Programme müssen mit allen oben genannten und mehr Arten von Daten arbeiten. Zur Hölle, ich möchte nicht 30 Tools testen, um 5-7-10 verschiedene Formate zu analysieren, die ich brauche, wenn ich das Problem in Minuten lösen kann. XML, JSON oder was auch immer interessieren mich nicht! Ich brauche eine einzige Lösung für alle.
Als Beispiel: Mein SmartHome-Programm führt unsere Häuser. Dabei liest es eine Vielzahl von Daten in zu vielen verschiedenen Formaten, die ich nicht kontrollieren kann. Ich verwende niemals dedizierte, geeignete Tools, da ich nicht mehr als Minuten mit dem Lesen der benötigten Daten verbringen möchte. Mit FS- und RS-Anpassungen funktioniert diese awk-Lösung perfekt für jedes Textformat. Es ist jedoch möglicherweise nicht die richtige Antwort, wenn Ihre Hauptaufgabe darin besteht, hauptsächlich mit vielen Daten in diesem Format zu arbeiten!
Das Problem, XML von Bash zu analysieren, hatte ich gestern. So mache ich das für jedes hierarchische Datenformat. Als Bonus - Ich ordne den Variablen in einem Bash-Skript Daten direkt zu.
Um die Lesbarkeit zu verbessern, werde ich die Lösung schrittweise vorstellen. Aus den OP-Testdaten habe ich eine Datei erstellt: test.xml
Analysieren Sie das XML in Bash und extrahieren Sie die Daten in 90 Zeichen:
Normalerweise verwende ich eine besser lesbare Version, da es im wirklichen Leben einfacher ist, Änderungen vorzunehmen, da ich häufig anders testen muss:
Es ist mir egal, wie das Format heißt. Ich suche nur die einfachste Lösung. In diesem speziellen Fall kann ich anhand der Daten erkennen, dass Newline das Datensatztrennzeichen (RS) und das <> Begrenzungsfeld (FS) ist. In meinem ursprünglichen Fall hatte ich eine komplizierte Indizierung von 6 Werten innerhalb von zwei Datensätzen, um sie zu verknüpfen und festzustellen, wann die Daten vorhanden sind, plus Felder (Datensätze), die möglicherweise vorhanden sind oder nicht. Es dauerte 4 Zeilen awk, um das Problem perfekt zu lösen. Passen Sie die Idee also an jeden Bedarf an, bevor Sie sie verwenden!
Der zweite Teil sieht einfach so aus, als ob eine Zeichenfolge in einer Zeile (RS) gesucht wird, und wenn ja, werden die erforderlichen Felder (FS) ausgedruckt. Ich habe ungefähr 30 Sekunden gebraucht, um den letzten Befehl, den ich auf diese Weise verwendet habe, zu kopieren und anzupassen (viermal länger). Und das ist alles! Fertig in 90 Zeichen.
Aber ich muss die Daten in meinem Skript immer ordentlich in Variablen umwandeln. Ich teste die Konstrukte zuerst so:
In einigen Fällen verwende ich printf anstelle von print. Wenn ich sehe, dass alles gut aussieht, beende ich einfach die Zuweisung von Werten zu Variablen. Ich weiß, dass viele denken, "eval" sei "böse", keine Notwendigkeit zu kommentieren :) Trick funktioniert seit Jahren perfekt in allen vier meiner Netzwerke. Aber lernen Sie weiter, wenn Sie nicht verstehen, warum dies eine schlechte Praxis sein kann! Inklusive Bash-Variablenzuweisungen und großem Abstand benötigt meine Lösung 120 Zeichen, um alles zu erledigen.
Antworten:
Dies ist wirklich nur eine Erklärung von Yuzems Antwort, aber ich hatte nicht das Gefühl, dass so viel an jemand anderem bearbeitet werden sollte, und Kommentare erlauben keine Formatierung, also ...
Nennen wir das "read_dom" anstelle von "rdom", platzieren Sie es ein wenig und verwenden Sie längere Variablen:
Okay, es definiert eine Funktion namens read_dom. In der ersten Zeile wird IFS (das Eingabefeldtrennzeichen) für diese Funktion lokalisiert und in> geändert. Das heißt, wenn Sie Daten lesen, anstatt sie automatisch auf Leerzeichen, Tabulatoren oder Zeilenumbrüche aufzuteilen, werden sie auf '>' aufgeteilt. In der nächsten Zeile wird angegeben, dass Eingaben von stdin gelesen werden sollen. Anstatt an einer neuen Zeile anzuhalten, halten Sie an, wenn Sie ein '<' (das -d für Deliminator-Flag) sehen. Was gelesen wird, wird dann mit dem IFS aufgeteilt und der Variablen ENTITY und CONTENT zugewiesen. Nehmen Sie also Folgendes:
Der erste Aufruf,
read_dom
um eine leere Zeichenfolge zu erhalten (da das '<' das erste Zeichen ist). Das wird von IFS in nur '' aufgeteilt, da es kein '>' Zeichen gibt. Read weist dann beiden Variablen eine leere Zeichenfolge zu. Der zweite Aufruf erhält die Zeichenfolge 'tag> value'. Das wird dann vom IFS in die beiden Felder 'tag' und 'value' aufgeteilt. Read weist dann die Variablen wie folgt zu:ENTITY=tag
undCONTENT=value
. Der dritte Aufruf erhält die Zeichenfolge '/ tag>'. Das wird vom IFS in die beiden Felder '/ tag' und '' aufgeteilt. Read weist dann die Variablen wie folgt zu:ENTITY=/tag
undCONTENT=
. Der vierte Aufruf gibt einen Status ungleich Null zurück, da das Dateiende erreicht ist.Jetzt hat seine while-Schleife ein wenig aufgeräumt, um dem oben genannten zu entsprechen:
In der ersten Zeile steht nur: "Während die Funktion read_dom den Status Null zurückgibt, gehen Sie wie folgt vor." In der zweiten Zeile wird überprüft, ob die Entität, die wir gerade gesehen haben, "Titel" ist. In der nächsten Zeile wird der Inhalt des Tags wiedergegeben. Die vier Zeilen werden beendet. Wenn es nicht die Titelentität war, wird die Schleife in der sechsten Zeile wiederholt. Wir leiten "xhtmlfile.xhtml" in die Standardeingabe (für die
read_dom
Funktion) und die Standardausgabe in "titleOfXHTMLPage.txt" (das Echo von früher in der Schleife) um.Geben Sie nun Folgendes an (ähnlich wie beim Auflisten eines Buckets in S3) für
input.xml
:und die folgende Schleife:
Du solltest bekommen:
Wenn wir also eine
while
Schleife wie die von Yuzem geschrieben haben:Wir würden eine Liste aller Dateien im S3-Bucket erhalten.
BEARBEITEN Wenn es aus irgendeinem Grund
local IFS=\>
bei Ihnen nicht funktioniert und Sie es global festlegen, sollten Sie es am Ende der Funktion wie folgt zurücksetzen:Andernfalls wird jede Zeilenaufteilung, die Sie später im Skript vornehmen, durcheinander gebracht.
BEARBEITEN 2 Um Attributname / Wert-Paare aufzuteilen, können Sie Folgendes erweitern
read_dom()
:Schreiben Sie dann Ihre Funktion, um die gewünschten Daten zu analysieren und abzurufen:
Dann, während Sie
read_dom
anrufenparse_dom
:Geben Sie dann das folgende Beispiel-Markup an:
Sie sollten diese Ausgabe erhalten:
EDIT 3 Ein anderer Benutzer gab an, Probleme mit FreeBSD zu haben, und schlug vor, den Exit-Status vor dem Lesen zu speichern und am Ende von read_dom zurückzugeben.
Ich sehe keinen Grund, warum das nicht funktionieren sollte
quelle
IFS=\< read ...
, wodurch nur IFS für den Leseaufruf festgelegt wird. (Beachten Sie, dass ich die Praxis desread
Parsen von XML in keiner Weise befürworte , und ich glaube, dass dies mit Gefahren behaftet ist und vermieden werden sollte.)Sie können dies sehr einfach mit nur Bash tun. Sie müssen nur diese Funktion hinzufügen:
Jetzt können Sie rdom wie read verwenden, aber für HTML-Dokumente. Beim Aufruf von rdom wird das Element der Variablen E und der Inhalt der Variable C zugewiesen.
Zum Beispiel, um das zu tun, was Sie tun wollten:
quelle
Zu den Befehlszeilentools, die über Shell-Skripte aufgerufen werden können, gehören:
Ich verwende auch xmllint und xsltproc mit kleinen XSL-Transformationsskripten, um die XML-Verarbeitung über die Befehlszeile oder in Shell-Skripten durchzuführen.
quelle
Sie können das Dienstprogramm xpath verwenden. Es wird mit dem Perl XML-XPath-Paket installiert.
Verwendung:
oder XMLStarlet . Um es auf opensuse zu installieren, verwenden Sie:
oder versuchen Sie es
cnf xml
auf anderen Plattformen.quelle
xpath
vorinstallierte Version nicht für die Verwendung als Komponente in Skripten geeignet. Siehe z. B. stackoverflow.com/questions/15461737/… für eine Ausarbeitung.apt-get install xmlstarlet
Das ist ausreichend ...
quelle
apt-get install libxml-xpath-perl
.Schauen Sie sich XML2 unter http://www.ofb.net/~egnor/xml2/ an , das XML in ein zeilenorientiertes Format konvertiert.
quelle
Ausgehend von der Antwort des Chad ist hier die KOMPLETTE Arbeitslösung zum Parsen von UML mit korrekter Behandlung von Kommentaren mit nur 2 kleinen Funktionen (mehr als 2 bu können Sie alle mischen). Ich sage nicht, dass chads überhaupt nicht funktioniert hat, aber es gab zu viele Probleme mit schlecht formatierten XML-Dateien: Sie müssen also etwas kniffliger sein, um mit Kommentaren und falsch platzierten Leerzeichen / CR / TAB / etc. Zu umgehen.
Der Zweck dieser Antwort besteht darin, jedem, der UML ohne komplexe Tools mit Perl, Python oder etwas anderem analysieren muss, sofort einsatzbereite Bash-Funktionen zur Verfügung zu stellen. Ich kann weder cpan noch Perl-Module für das alte Produktionsbetriebssystem installieren, an dem ich arbeite, und Python ist nicht verfügbar.
Zunächst eine Definition der in diesem Beitrag verwendeten UML-Wörter:
EDIT: aktualisierte Funktionen, mit Handle von:
Die Funktionen sind zunächst die xml_read_dom, die von xml_read rekursiv aufgerufen wird:
und der zweite:
und schließlich die Funktionen rtrim, trim und echo2 (to stderr):
Färbung:
Oh, und Sie müssen zunächst einige ordentliche kolorierende dynamische Variablen definieren und auch exportieren:
Wie man all das Zeug lädt:
Entweder wissen Sie, wie Sie Funktionen erstellen und über FPATH (ksh) oder eine Emulation von FPATH (bash) laden.
Wenn nicht, kopieren Sie einfach alles in die Befehlszeile.
Wie funktioniert es:
Im Debug-Modus (-d) werden Kommentare und analysierte Attribute auf stderr gedruckt
quelle
./read_xml.sh: line 22: (-1): substring expression < 0
?[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
Mir ist kein reines Shell-XML-Parsing-Tool bekannt. Sie benötigen also höchstwahrscheinlich ein Tool, das in einer anderen Sprache geschrieben ist.
Mein XML :: Twig Perl-Modul enthält ein solches Tool:
xml_grep
Hier können Sie wahrscheinlich schreiben, als was Sie möchtenxml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt
(die-t
Option gibt Ihnen das Ergebnis als Text anstelle von XML).quelle
Ein weiteres Kommandozeilen-Tool ist mein neues Xidel . Es unterstützt auch XPath 2 und XQuery, im Gegensatz zu dem bereits erwähnten xpath / xmlstarlet.
Der Titel kann wie folgt gelesen werden:
Und es hat auch eine coole Funktion, um mehrere Variablen nach Bash zu exportieren. Beispielsweise
Legt
$title
den Titel und$imgcount
die Anzahl der Bilder in der Datei fest, die so flexibel sein sollten wie das direkte Parsen in Bash.quelle
Nun, Sie können das Dienstprogramm xpath verwenden. Ich denke, Perls XML :: Xpath enthält es.
quelle
Nach einigen Recherchen zur Übersetzung der Dateipfade in XML-Dateien zwischen Linux- und Windows-Formaten fand ich interessante Tutorials und Lösungen zu folgenden Themen:
quelle
Zwar gibt es einige vorgefertigte Konsolendienstprogramme, die möglicherweise das tun, was Sie möchten, aber es wird wahrscheinlich weniger Zeit in Anspruch nehmen, einige Codezeilen in einer universellen Programmiersprache wie Python zu schreiben, die Sie problemlos erweitern und anpassen können Deine Bedürfnisse.
Hier ist ein Python-Skript, das
lxml
zum Parsen verwendet wird: Es verwendet den Namen einer Datei oder einer URL als ersten Parameter, einen XPath-Ausdruck als zweiten Parameter und druckt die Zeichenfolgen / Knoten, die dem angegebenen Ausdruck entsprechen.Beispiel 1
lxml
kann mit installiert werdenpip install lxml
. Auf Ubuntu können Sie verwendensudo apt install python-lxml
.Verwendung
lxml
akzeptiert auch eine URL als Eingabe:Beispiel 2
Ein einmaliges Skript, das dem engen Zweck dient, Modulnamen aus einer Apache-Maven-Datei zu extrahieren. Beachten Sie, wie dem Knotennamen (
module
) der Standard-Namespace vorangestellt wird{http://maven.apache.org/POM/4.0.0}
:pom.xml :
module_extractor.py :
quelle
pip install
Overapt-get
oder einenyum
Call rechtfertigen . Vielen Dank!Die Methode von Yuzem kann verbessert werden, indem die Reihenfolge der
<
und>
-Zeichen in derrdom
Funktion und die Variablenzuweisungen umgekehrt werden , so dass:wird:
Wenn das Parsen nicht so durchgeführt wird, wird das letzte Tag in der XML-Datei nie erreicht. Dies kann problematisch sein, wenn Sie am Ende der
while
Schleife eine weitere XML-Datei ausgeben möchten.quelle
Dies funktioniert, wenn Sie XML-Attribute wünschen:
quelle
Obwohl es so aussieht, als ob "niemals XML, JSON ... von Bash ohne ein geeignetes Tool analysieren" ein guter Rat ist, bin ich anderer Meinung. Wenn dies ein Nebenjob ist, ist es schwierig, nach dem richtigen Werkzeug zu suchen und es dann zu lernen ... Awk kann es in Minuten erledigen. Meine Programme müssen mit allen oben genannten und mehr Arten von Daten arbeiten. Zur Hölle, ich möchte nicht 30 Tools testen, um 5-7-10 verschiedene Formate zu analysieren, die ich brauche, wenn ich das Problem in Minuten lösen kann. XML, JSON oder was auch immer interessieren mich nicht! Ich brauche eine einzige Lösung für alle.
Als Beispiel: Mein SmartHome-Programm führt unsere Häuser. Dabei liest es eine Vielzahl von Daten in zu vielen verschiedenen Formaten, die ich nicht kontrollieren kann. Ich verwende niemals dedizierte, geeignete Tools, da ich nicht mehr als Minuten mit dem Lesen der benötigten Daten verbringen möchte. Mit FS- und RS-Anpassungen funktioniert diese awk-Lösung perfekt für jedes Textformat. Es ist jedoch möglicherweise nicht die richtige Antwort, wenn Ihre Hauptaufgabe darin besteht, hauptsächlich mit vielen Daten in diesem Format zu arbeiten!
Das Problem, XML von Bash zu analysieren, hatte ich gestern. So mache ich das für jedes hierarchische Datenformat. Als Bonus - Ich ordne den Variablen in einem Bash-Skript Daten direkt zu.
Um die Lesbarkeit zu verbessern, werde ich die Lösung schrittweise vorstellen. Aus den OP-Testdaten habe ich eine Datei erstellt: test.xml
Analysieren Sie das XML in Bash und extrahieren Sie die Daten in 90 Zeichen:
Normalerweise verwende ich eine besser lesbare Version, da es im wirklichen Leben einfacher ist, Änderungen vorzunehmen, da ich häufig anders testen muss:
Es ist mir egal, wie das Format heißt. Ich suche nur die einfachste Lösung. In diesem speziellen Fall kann ich anhand der Daten erkennen, dass Newline das Datensatztrennzeichen (RS) und das <> Begrenzungsfeld (FS) ist. In meinem ursprünglichen Fall hatte ich eine komplizierte Indizierung von 6 Werten innerhalb von zwei Datensätzen, um sie zu verknüpfen und festzustellen, wann die Daten vorhanden sind, plus Felder (Datensätze), die möglicherweise vorhanden sind oder nicht. Es dauerte 4 Zeilen awk, um das Problem perfekt zu lösen. Passen Sie die Idee also an jeden Bedarf an, bevor Sie sie verwenden!
Der zweite Teil sieht einfach so aus, als ob eine Zeichenfolge in einer Zeile (RS) gesucht wird, und wenn ja, werden die erforderlichen Felder (FS) ausgedruckt. Ich habe ungefähr 30 Sekunden gebraucht, um den letzten Befehl, den ich auf diese Weise verwendet habe, zu kopieren und anzupassen (viermal länger). Und das ist alles! Fertig in 90 Zeichen.
Aber ich muss die Daten in meinem Skript immer ordentlich in Variablen umwandeln. Ich teste die Konstrukte zuerst so:
In einigen Fällen verwende ich printf anstelle von print. Wenn ich sehe, dass alles gut aussieht, beende ich einfach die Zuweisung von Werten zu Variablen. Ich weiß, dass viele denken, "eval" sei "böse", keine Notwendigkeit zu kommentieren :) Trick funktioniert seit Jahren perfekt in allen vier meiner Netzwerke. Aber lernen Sie weiter, wenn Sie nicht verstehen, warum dies eine schlechte Praxis sein kann! Inklusive Bash-Variablenzuweisungen und großem Abstand benötigt meine Lösung 120 Zeichen, um alles zu erledigen.
quelle