2016-07-23 3 views
-1

ich in einem Verzeichnis mehrere XML-Dateien haben, und ich würde verschiedene Arten von Daten von ihm in eine eine, tabellenartige Ausgabe (Tabs zwischen den Feldern) extrahieren möchten . Auch würde ich gerne Header (Spaltennamen) und eine boolesche Interpolation in einigen der Spalten haben.Wie Daten aus mehreren XML ist in eine Tabelle zu extrahieren, mit AWK

Ich habe 2 hergestellte Probe XML-Dateien, die unten zu finden sind, und ich möchte ein AWK Befehl haben, der durch alle Dateien in diesem Verzeichnis ausgeführt wird, und extrahieren Sie die folgenden Werte:

  1. der Name der Datei
  2. der Wert von "property1" (numerisch)
  3. der Wert von "property2" (boolean)
  4. Die Zeichenfolge "$ test1 $"
  5. Die Zeichenfolge "$ test2 $", wenn existiert

    • In der realen Verzeichnis habe ich mehr als 200 Dateien und ich würde sie alle gerne in der Ausgabe dargestellt werden, auch wenn einige von ihnen haben keine der oben genannten Werte.

    • Beachten Sie, dass die Werte "$ test1 $" und "$ test2 $" sind unter einem anderen übergeordneten Element. Die Elemente "property1" und "property2" (# 2 und # 3 in der obigen Liste) bleiben immer gleich, aber nicht unbedingt in derselben Reihenfolge (wie in meinen Eingabedateien unten gezeigt).

    • Ich weiß, wie man mit dem Dateinamen und einem der anderen Werte aus der obigen Liste zur gewünschten Ausgabe gelangt (mit dem eingebauten FILENAME-Parameter in AWK), aber ich kann nicht scheinen, zusätzliche Werte richtig hinzuzufügen.

    • Meines Wissens ist AWK das beste Werkzeug für eine solche Sache zu verwenden, aber wenn Sie von einem anderen Werkzeug denken, dass die gleiche Leistung bieten wird, dann bin ich mehr als in Ordnung mit ihm :-)

Bitte unten finden sowohl die XML-Dateien (die Eingangsdaten):

TextXML1.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<TestXML1> 
    <properties> 
     <property name="property1" value="500"></property> 
     <property name="property2" value="true"></property> 
    </properties> 
    <attrs> 
     <attr type='parameter' name='T1234'> 
      <parameter input='$test1$'></parameter> 
     </attr> 
     <attr type='parameter' name='H5H7'> 
      <parameter input='$test2$'></parameter> 
     </attr> 
    </attrs> 
</TestXML1> 

TestXML2.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<TestXML2> 
    <properties> 
     <property name="property2" value="False"></property> 
     <property name="property1" value="300"></property> 
    </properties> 
    <attrs> 
     <attr type='parameter' name='TD837'> 
      <parameter input='$test1$'></parameter> 
     </attr> 
     <attr type='parameter' name='JQE284'> 
      <parameter input='$test3$'></parameter> 
     </attr> 
    </attrs> 
</TestXML2> 

und die gewünschte Ausgabe:

File name property1 property2 $test1$  $test2$ 
TestXML1.xml 500  True  True  True 
TestXML2.xml 300  True  True  False 

Vielen Dank!

+5

'awk' im Allgemeinen ein schlechtes Werkzeug ist xml für das Parsen (weil XML nicht tatsächlich Linie basiert, und zwei äquivalente XML-Dateien können sehr unterschiedlich formatiert werden). In den meisten Fällen ist es besser, etwas zu verwenden, das XML tatsächlich analysieren kann (wie Python oder Perl oder Ruby oder ...). Bei der Frage "Wie schreibe ich diese Art von Fragen?" Erwarten wir normalerweise, dass Sie uns zuerst zeigen, was Sie selbst versucht haben. – larsks

+4

Verwenden Sie einen XML/HTML-Parser (xmllint, xmlstarlet ...). – Cyrus

+0

Bitte fügen Sie die XML in-line in die Frage ein. – Kusalananda

Antwort

1

Hier ist, wie alle zu extrahieren, die Namen, Werte und Eingaben mit GNU awk für die 3. arg übereinstimmen() und wahren multidimensionalen Arrays:

$ cat tst.awk 
match($0,/\<name="([^"]*)".*\<value="([^"]*)"/,a) { n2v[a[1]][ARGIND] = a[2] } 
match($0,/\<input=\047([^\047]*)\047/,a) { inputs[a[1]][ARGIND] } 
END{ 
    printf "Filename" 
    for (name in n2v) { 
     printf "%s%s", OFS, name 
    } 
    for (input in inputs) { 
     printf "%s%s", OFS, input 
    } 
    print "" 

    for (fileNr=1; fileNr<ARGC; fileNr++) { 
     printf "%s", ARGV[fileNr] 
     for (name in n2v) { 
      printf "%s%s", OFS, (fileNr in n2v[name] ? n2v[name][fileNr] : "N/A") 
     } 
     for (input in inputs) { 
      printf "%s%s", OFS, (fileNr in inputs[input] ? "True" : "False") 
     } 
     print "" 
    } 
} 

$ awk -f tst.awk TestXML1.xml TestXML2.xml 
Filename property1 property2 $test1$ $test2$ $test3$ 
TestXML1.xml 500 true True True False 
TestXML2.xml 300 false True False True 

Sie können es leicht zwicken, um nur diejenigen auswählen du kümmerst dich um.

+1

Vielen Dank Ed! Es funktionierte. – K1000

0

Wie verschiedene andere haben bereits darauf hingewiesen, sollten Sie nicht zeilenorientierte Tools wie awk verwenden XML zu verarbeiten. Verwenden Sie stattdessen ein XML-fähiges Tool wie xmlstarlet.Hier ist eine Teillösung für Ihr Problem:

xmlstarlet sel -t -v //property/@value -nl -v //parameter/@input -nl TestXML1.xml TestXML2.xml 
Verwandte Themen