48 Stimmen

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 zu extrahieren, was sich in der <job..> </job> Tags, in diesem Fall programmin. Dies sollte in der Linux-Eingabeaufforderung mit grep/sed/awk geschehen.

0 Stimmen

Wenn Ihre XML-Datei dies enthalten würde: <?xml version="1.0" encoding="utf-8"?> <job xmlns=" sample.com/">Tom & Jerry</job> würden Sie wollen, dass das Ergebnis XML-Escaping in Ruhe gelassen wird: Tom & Jerry oder möchten Sie, dass das Escaping rückgängig gemacht wird, wie es ein XML-Parser tun würde: Tom & Jerry Wenn letzteres der Fall ist, weiß ich leider nicht, wie man das mit Unix-Textprogrammen macht.

0 Stimmen

@Paul s/&amp;/\&/g , auch für &quot; usw., natürlich wird es nicht für benutzerdefinierte Entitäten usw. verallgemeinert.

0 Stimmen

68voto

amarillion Punkte 23299

Wollen Sie wirklich müssen nur diese Werkzeuge verwenden? Sie sind nicht für die XML-Verarbeitung konzipiert, und obwohl es möglich ist, etwas zu erhalten, das die meiste Zeit über gut funktioniert, wird es in Grenzfällen wie Kodierung, Zeilenumbrüchen usw. versagen.

Ich empfehle xml_grep:

xml_grep 'job' jobs.xml --text_only

Dies ergibt die Ausgabe:

programming

Unter ubuntu/debian ist xml_grep im Paket xml-twig-tools enthalten.

0 Stimmen

Eine genaue Installationsanleitung für xml_grep wäre toll

6 Stimmen

Sudo apt-get install xml-twig-tools

1 Stimmen

"grep" ist nur ein Synonym für eine mühelose Textsuche.

17voto

Vijay Punkte 62277
 grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"

1 Stimmen

Nur, dass es fehlschlägt, wenn die Tags in separaten Zeilen stehen

8 Stimmen

Es gibt etwa ein Dutzend anderer Möglichkeiten, wie wohlgeformtes XML dies verhindern kann.

12voto

lmxy Punkte 269

Verwendung von xmlstarlet:

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

4 Stimmen

Es gibt eine große Anzahl verschiedener Tools, die die Standard-XPath-Notation verwenden, um Informationen aus XML zu extrahieren. xmlstarlet ist nur einer. Andere umfassen xmllint , xpath , usw. Siehe stackoverflow.com/questions/15461737/

12voto

Sobrique Punkte 52278

Bitte verwenden Sie kein zeilen- und regexbasiertes Parsing von XML. Das ist eine schlechte Idee. Sie können semantisch identisches XML mit unterschiedlicher Formatierung haben, und Regex und zeilenbasiertes Parsing kommen damit einfach nicht zurecht.

Dinge wie unäre Tags und variabler 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>

Damit ist hoffentlich klar, warum es schwierig ist, einen Regex/Zeilen-basierten Parser zu erstellen? Glücklicherweise müssen Sie das nicht. Viele Skriptsprachen haben mindestens eine, manchmal auch mehrere Parser-Optionen.

Wie ein Vorposter bereits angedeutet hat - xml_grep ist verfügbar. Das ist eigentlich ein Tool, das auf dem XML::Twig Perl-Bibliothek. Sie verwendet jedoch "xpath-Ausdrücke", um etwas zu finden, und unterscheidet zwischen Dokumentstruktur, Attributen und "Inhalt".

Z.B.:

xml_grep 'job' jobs.xml --text_only

Im Interesse besserer Antworten finden Sie hier jedoch einige Beispiele für die Erstellung eigener Antworten auf der Grundlage Ihrer Quelldaten:

Erster Weg:

Utilice twig handlers die Elemente eines bestimmten Typs auffängt und auf sie einwirkt. Der Vorteil dieser Vorgehensweise ist, dass das XML "während der Bearbeitung" geparst wird und Sie es bei Bedarf während der Bearbeitung ändern können. Dies ist besonders nützlich, um "verarbeitetes" XML zu verwerfen, wenn Sie mit großen Dateien arbeiten, indem Sie purge o flush :

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

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

Das wird die <> um Eingaben entgegenzunehmen (über die Pipeline oder über die Befehlszeile angegeben) ./myscript somefile.xml ) und verarbeiten sie - jede job Element, wird der zugehörige Text extrahiert und gedruckt. (Sie möchten vielleicht print $_ -> text,"\n" um einen Zeilenvorschub einzufügen).

Da es auf "Job"-Elemente abgestimmt ist, wird es auch auf verschachtelte Job-Elemente abgestimmt:

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

wird zweimal übereinstimmen, aber auch einen Teil der Ausgabe zweimal ausgeben. Sie können jedoch eine Übereinstimmung mit /job wenn Sie dies bevorzugen. Nützlich - damit können Sie z. B. ein Element drucken und löschen oder ein Element kopieren und einfügen und dabei die XML-Struktur ändern.

Alternativ - zuerst parsen und dann anhand der Struktur "drucken":

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

Als job Ihr Root-Element ist, brauchen wir nur den Text zu drucken.

Aber wir können ein bisschen anspruchsvoller sein und auf Folgendes achten job o /job und drucken Sie stattdessen genau das:

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

Sie können verwenden XML::Twig s pretty_print um auch Ihre XML-Datei neu zu formatieren:

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

Es gibt eine Vielzahl von Ausgabeformaten, aber für einfachere XML-Dateien (wie Ihre) sehen die meisten ziemlich ähnlich aus.

8voto

ghostdog74 Punkte 305138

Verwenden Sie einfach awk, Sie brauchen keine anderen externen Tools. Unten funktioniert, wenn die gewünschten Tags in Multitine erscheinen.

$ 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

1 Stimmen

</ job> ist gültig, aber Ihr Skript erkennt es nicht. <!-- </job> --> ist ein Kommentar, der ignoriert werden muss (und <!CDATA[[ </job> ]]> sind wörtliche Daten), aber Ihr Skript weiß nicht, dass dass . Und dann gibt es Fälle, in denen eine DTD neue Makros definiert, so dass &foo; zu etwas lokal Spezifiziertem erweitert wird, und die einfachen Fälle, wie die Notwendigkeit, die &amp; a & . Der Versuch, das XML-Parsing (oder schlimmer noch, die XML-Generierung) selbst zu übernehmen, führt zu einer Unzahl von Eckfällen und kleinen Details, die einzeln überprüft und behoben werden müssen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X