Ich habe eine XML-Datei mit dem Inhalt:
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
Ich brauche einen Weg, um herauszufinden, was in den <job..>
</job>
-Tags enthalten ist, in diesem Fall programmin. Dies sollte über den Linux-Befehl Prompt mit grep/sed/awk erfolgen.
Müssen Sie wirklich nur diese Werkzeuge verwenden ? Sie sind nicht für die XML-Verarbeitung konzipiert, und obwohl es möglich ist, dass etwas funktioniert, das die meiste Zeit in Ordnung ist, schlägt dies bei Edge-Fällen wie Codierung, Zeilenumbrüchen usw. fehl.
Ich empfehle xml_grep:
xml_grep 'job' jobs.xml --text_only
Welches gibt die Ausgabe:
programming
Unter Ubuntu/Debian befindet sich xml_grep im Paket xml-twig-tools.
grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"
Xmlstarlet verwenden:
echo '<job xmlns="http://www.sample.com/">programming</job>' | \
xmlstarlet sel -N var="http://www.sample.com/" -t -m "//var:job" -v '.'
Bitte verwenden Sie kein Zeilen- und Regex-basiertes Parsing für XML. Das ist eine schlechte Idee. Sie können semantisch identisches XML mit unterschiedlichen Formatierungen verwenden, und regex- und zeilenbasiertes Parsing kann damit einfach nicht umgehen.
Dinge wie unäre Tags und variabler Zeilenumbruch - diese Ausschnitte 'sagen' dasselbe:
<root>
<sometag val1="fish" val2="carrot" val3="narf"></sometag>
</root>
<root>
<sometag
val1="fish"
val2="carrot"
val3="narf"></sometag>
</root>
<root
><sometag
val1="fish"
val2="carrot"
val3="narf"
></sometag></root>
<root><sometag val1="fish" val2="carrot" val3="narf"/></root>
Hoffentlich wird dadurch klar, warum es schwierig ist, einen regex/line-basierten Parser zu erstellen? Zum Glück brauchen Sie das nicht. Viele Skriptsprachen haben mindestens eine, manchmal mehr Parser-Option.
Wie bereits in einem früheren Poster erwähnt, ist xml_grep
verfügbar. Das ist eigentlich ein Werkzeug, das auf der Bibliothek XML::Twig
Perl basiert. Was jedoch geschieht, verwendet 'xpath-Ausdrücke', um etwas zu finden, und unterscheidet zwischen Dokumentstruktur, Attributen und 'Inhalt'.
Z.B.:
xml_grep 'job' jobs.xml --text_only
Um jedoch bessere Antworten zu erhalten, finden Sie hier einige Beispiele für "Rollen Sie Ihre eigenen", die auf Ihren Quelldaten basieren:
Erster Weg:
Verwenden Sie twig handlers
, um Elemente eines bestimmten Typs abzufangen und auf sie einzuwirken. Der Vorteil, wenn Sie dies auf diese Weise tun, besteht darin, dass Sie die XML-Daten während der Ausführung analysieren und bei Bedarf während des Flugs ändern können. Dies ist besonders nützlich, um "verarbeitete" XML-Dateien zu verwerfen, wenn Sie mit großen Dateien arbeiten, und zwar mit purge
oder flush
:
#!/usr/bin/Perl
use strict;
use warnings;
use XML::Twig;
XML::Twig->new(
twig_handlers => {
'job' => sub { print $_ ->text }
}
)->parse( <> );
<>
wird verwendet, um eine Eingabe zu übernehmen (eingespeist oder über die Befehlszeile ./myscript somefile.xml
angegeben) und zu verarbeiten - jedes job
-Element extrahiert und druckt den zugehörigen Text. (Vielleicht möchten Sie, dass print $_ -> text,"\n"
einen Zeilenvorschub einfügt).
Da es für 'Job'-Elemente passt, passt es auch zu verschachtelten Job-Elementen:
<job>programming
<job>anotherjob</job>
</job>
Stimmt zweimal überein, druckt aber auch einen Teil der Ausgabe zweimal. Sie können jedoch auch auf /job
passen, wenn Sie möchten. Nützlich - damit können Sie z. ein Element drucken und löschen oder ein Element kopieren und einfügen, um die XML-Struktur zu ändern.
Alternativ können Sie zuerst analysieren und nach Struktur drucken:
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> root -> text;
Da job
Ihr Wurzelelement ist, müssen Sie nur den Text drucken.
Aber wir können ein bisschen anspruchsvoller sein und suchen nach job
oder /job
und drucken das stattdessen:
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> findnodes('/job',0)->text;
Mit der Option XML::Twig
s pretty_print
können Sie auch Ihre XML-Datei neu formatieren:
XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( <> ) -> print;
Es gibt verschiedene Ausgabeformatoptionen, aber für einfacheres XML (wie Ihr) sehen die meisten ziemlich ähnlich aus.
verwenden Sie einfach awk, keine anderen externen Werkzeuge. Nachfolgend gilt, wenn die gewünschten Tags in Multitine angezeigt werden.
$ cat file
test
<job xmlns="http://www.sample.com/">programming</job>
<job xmlns="http://www.sample.com/">
programming</job>
$ awk -vRS="</job>" '{gsub(/.*<job.*>/,"");print}' file
programming
programming
Gleiche Zeile vorausgesetzt, Eingabe von stdin:
sed -ne '/<\/job>/ { s/<[^>]*>\(.*\)<\/job>/\1/; p }'
hinweise: -n
stoppt die automatische Ausgabe von alles; -e
bedeutet, dass es sich um ein Einzeiler (kein Skript) handelt. /<\/job>
verhält sich wie ein grep; s
entfernt die Attribute von opentag + und das Endtag; ;
ist eine neue Anweisung. p
druckt; {}
bewirkt, dass das grep auf beide Anweisungen als eine Einheit angewendet wird.
Verwenden von sed command:
Beispiel:
$ cat file.xml
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
$ cat file.xml | sed -ne '/<heading>/s#\s*<[^>]*>\s*##gp'
Reminder
Erklärung:
cat file.xml | sed -ne '/<pattern_to_find>/s#\s*<[^>]*>\s*##gp'
n
- unterdrückt den Druck aller Zeilene
- Skript
/<pattern_to_find>/
- findet Zeilen, die ein angegebenes Muster enthalten, z. B. <heading>
als nächstes ist der Ersetzungsbestandteil s///p
that, der alles außer dem gewünschten Wert entfernt, wobei /
zur besseren Lesbarkeit durch #
ersetzt wird:
s#\s*<[^>]*>\s*##gp
\s*
- schließt Leerzeichen ein, falls vorhanden (am Ende dasselbe)<[^>]*>
steht für <xml_tag>
als nicht gieriger alternativer Grund für regex. <.*?>
funktioniert nicht für sed
g - ersetzt alles, z. xml </xml_tag>
-Tag wird geschlossen
Ein bisschen spät in die Show.
xmlcutty schneidet Knoten aus XML heraus:
$ cat file.xml
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
<job xmlns="http://www.sample.com/">designing</job>
<job xmlns="http://www.sample.com/">managing</job>
<job xmlns="http://www.sample.com/">teaching</job>
Das Argument path
benennt den Pfad zu dem Element, das Sie ausschneiden möchten. Da wir an den Tags überhaupt nicht interessiert sind, benennen wir das Tag in \n
um, sodass wir eine Nizza-Liste erhalten:
$ xmlcutty -path /job -rename '\n' file.xml
programming
designing
managing
teaching
Beachten Sie, dass das XML zu Beginn nicht gültig war (kein Stammelement). xmlcutty kann auch mit leicht defektem XML arbeiten.
Wie wäre es mit:
cat a.xml | grep '<job' | cut -d '>' -f 2 | cut -d '<' -f 1