2010-02-08 2 views
31

Ich habe eine XML-Datei mit dem Inhalt:Extraktion von Daten aus einer einfachen XML-Datei

<?xml version="1.0" encoding="utf-8"?> 
<job xmlns="http://www.sample.com/">programming</job> 

Ich muß einen Weg zu extrahieren, was in den <job..></job> Tags ist, PROGRAMMIE in diesem Fall. Dies sollte in der Linux-Eingabeaufforderung mit grep/sed/awk erfolgen.

+0

Wenn Ihre XML-Datei enthalten diese: Tom & Jerry würden Sie das Ergebnis XML haben, allein gelassen von Umschreibungen: Tom & Jerry oder würden Sie das entweichende rückgängig gemacht werden, als XML-Parser möchte: Tom & Jerry Wenn es ist letzteres, sorry, ich weiß nicht, wie man das mit Unix-Text-Tools macht. –

+0

@Paul's/&/\ &/g', das gleiche gilt für '"' etc, natürlich verallgemeinert es nicht für benutzerdefinierte Einheiten etc. – 13ren

Antwort

51

Sie tun wirklich zu Verwendung haben nur diese Werkzeuge? Sie sind nicht für die XML-Verarbeitung entwickelt, und obwohl es möglich ist, etwas zu bekommen, das OK die meiste Zeit arbeitet, wird er am Rand Fällen fehlschlagen, wie Codierung, Zeilenumbrüche usw.

Ich empfehle xml_grep:

xml_grep 'job' jobs.xml --text_only 

, die den Ausgang gibt:

programming 

auf ubuntu/debian ist xml_grep im xml-Zweig-Tools-Paket.

+0

Enge Installationsanweisungen wären großartig für xml_grep –

+0

sudo apt-get installieren xml-twig-tools – FredFury

0

Wie wäre:

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

UUOC. 'grep ' ghostdog74

+0

@ghost * aber aber, ich denke, es ist sauberer/schöner/nicht so viel Abfall/mein Privileg, Prozesse zu verschwenden! * Http://partmaps.org/era/unix/award.html#cat (eigentlich, ich denke, es ist einfacher, den Dateinamen zu bearbeiten, weil näher am Anfang) – 13ren

+3

Wenn Sie ' Thor

11
grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<" 
+0

nur, dass es fehlschlägt, wenn die Tags in separaten Zeilen sind – ghostdog74

+7

Es gibt ungefähr ein Dutzend andere Möglichkeiten, die wohlgeformtes XML zum Scheitern bringen kann. –

6

Verwenden Sie einfach awk, keine anderen externen Tools. Unten funktioniert, wenn Ihre gewünschten Tags in mehreren Sprachen 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 
+0

'' ist gültig, aber Ihr Skript erkennt es nicht. '

+3

Es gibt eine beträchtliche Anzahl verschiedener Tools, die die Standard-XPath-Notation verwenden, um Informationen aus XML zu extrahieren - "xmlstarlet" ist nur eine davon. Andere enthalten 'xmllint',' xpath' usw. Siehe http://stackoverflow.com/questions/15461737/how-to-execute-xpath-one-liner-fromshell – tripleee

8

Bitte verwenden Sie keine Linie und regex basiert Parsen von XML. Es ist eine schlechte Idee. Sie können semantisch identischen XML mit verschiedenen Formatierungen haben, und regex und zeilenbasiertes Parsing können einfach nicht damit umgehen.

Dinge wie einstellige Tags und variable Zeilenumbruch - diese Schnipsel 'sagen das Gleiche:

<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 macht klar, warum eine regex/Linie basierte Parser macht schwierig ist? Zum Glück brauchen Sie das nicht. Viele Skriptsprachen haben mindestens eine, manchmal mehr Parser-Optionen.

Wie ein vorheriges Plakat angedeutet hat - xml_grep ist verfügbar. Das ist eigentlich ein Tool basierend auf der XML::Twig Perl-Bibliothek. Was es jedoch tut, ist "XPath-Ausdrücke" zu verwenden, um etwas zu finden, und unterscheidet zwischen Dokumentenstruktur, Attributen und "Inhalt".

z.:

xml_grep 'job' jobs.xml --text_only 

jedoch im Interesse bessere Antworten zu machen, hier ein paar Beispiele für ‚rollen Sie Ihre eigenen‘ Daten auf der Grundlage Ihrer Quelle:

Erster Weg:

Verwenden twig handlers, die Elemente fängt einer bestimmten Art und handelt auf sie. Der Vorteil besteht darin, dass der XML-Code analysiert wird und Sie ihn im Flug ändern können, wenn Sie möchten. Dies ist besonders nützlich für ‚verarbeitet‘ XML verwerfen, wenn Sie mit großen Dateien arbeiten, purge oder flush mit:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

XML::Twig->new(
    twig_handlers => { 
     'job' => sub { print $_ ->text } 
    } 
    )->parse(<>); 

Welche <> zu nehmen Eingang (verrohrt in oder spezifizierte über Command ./myscript somefile.xml) und Verfahren verwenden es - jedes job Element, wird es jeden Text extrahieren und drucken. (Möglicherweise möchten Sie print $_ -> text,"\n" einen Zeilenvorschub einfügen).

Weil es auf ‚job‘ Elemente zusammenbringt, wird es auch auf verschachtelte Job Elemente entsprechen:

<job>programming 
    <job>anotherjob</job> 
</job> 

zweimal, passen aber einige der Ausgang zweimal drucken. Sie können jedoch auf /job statt, wenn Sie bevorzugen. Nützlich - so können Sie z. drucke und lösche ein Element oder kopiere und füge eines ein, das die XML-Struktur verändert.

Alternativ - analysieren zuerst und ‚Druck‘ auf Basis von Struktur:

my $twig = XML::Twig->new()->parse(<>); 
print $twig -> root -> text; 

Als job Ihr Wurzelelement ist, alles, was wir den Text ausdrucken tun müssen.

Aber wir können für job oder /job und drucken, die speziell stattdessen ein bisschen anspruchsvoller, und suchen sein: kann

my $twig = XML::Twig->new()->parse(<>); 
print $twig -> findnodes('/job',0)->text; 

Sie verwenden XML::Twig s pretty_print Option XML-formatieren zu:

XML::Twig->new('pretty_print' => 'indented_a')->parse(<>) -> print; 

Es gibt eine Vielzahl von Ausgabeformatoptionen, aber für einfacheres XML (wie Ihres) werden die meisten ziemlich ähnlich aussehen.

0

Ein bisschen zu spät zur Show.

xmlcutty schneidet Knoten aus XML:

$ 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> 

Die path Argument Namen der Pfad zu dem Element, das Sie aus schneiden möchten. In diesem Fall, da wir in den Tags überhaupt nicht daran interessiert sind, benennen wir den Tag zu \n, so erhalten wir eine schöne Liste:

$ xmlcutty -path /job -rename '\n' file.xml 
programming 
designing 
managing 
teaching 

Beachten Sie, dass der XML nicht gültig war mit (ohne Wurzel beginnen Element). xmlcutty kann auch mit leicht gebrochenem XML arbeiten.

2

Verwendung Sed Befehl:

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 

Erläuterung:

cat file.xml | sed -ne '/<pattern_to_find>/s#\s*<[^>]*>\s*##gp'

n - Unterdrückungs Drucken aller Linien
e - Skript

/<pattern_to_find>/ - findet Zeilen, die Muster angegeben enthalten, was zum Beispiel sein könnte <heading>

nächstes wird eine Substitution Teil s///p, die alles außer gewünschten Wert entfernt, wo / mit # zur besseren Lesbarkeit ersetzt:

s#\s*<[^>]*>\s*##gp
\s* - umfasst Weißräume falls vorhanden (gleiche am Ende)
<[^>]*> repräsentiert <xml_tag> als nicht-gierige Regex Alternative Ursache <.*?> funktioniert nicht für sed
g - ersetzt alles z Schließen xml </xml_tag> Tag

Verwandte Themen