it-swarm.com.de

Extraktion von Daten aus einer einfachen XML-Datei

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.

37
Zacky112

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.

63
amarillion
 grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"
12
Vijay

Xmlstarlet verwenden:

echo '<job xmlns="http://www.sample.com/">programming</job>' | \
   xmlstarlet sel -N var="http://www.sample.com/" -t -m "//var:job" -v '.'
9
lmxy

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::Twigs 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. 

9
Sobrique

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
8
ghostdog74

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.

5
13ren

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 Zeilen
e - Skript

/<pattern_to_find>/ - findet Zeilen, die ein angegebenes Muster enthalten, z. B. <heading>

als nächstes ist der Ersetzungsbestandteil s///pthat, 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

3
vldbnc

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.

0
miku

Wie wäre es mit:

cat a.xml | grep '<job' | cut -d '>' -f 2 | cut -d '<' -f 1
0
codaddict