Die Dünne
jq -r '(.[0] | keys_unsorted) as $keys | $keys, map([.[ $keys[] ]])[] | @csv'
oder:
jq -r '(.[0] | keys_unsorted) as $keys | ([$keys] + map([.[ $keys[] ]])) [] | @csv'
Die Details
Beiseite
Das Beschreiben der Details ist schwierig, da jq streamorientiert ist, was bedeutet, dass es mit einer Folge von JSON-Daten und nicht mit einem einzelnen Wert arbeitet. Der Eingabe-JSON-Stream wird in einen internen Typ konvertiert, der durch die Filter geleitet und am Ende des Programms in einem Ausgabestream codiert wird. Der interne Typ wird nicht von JSON modelliert und existiert nicht als benannter Typ. Dies lässt sich am einfachsten anhand der Ausgabe eines Bare-Index ( .[]
) oder des Komma-Operators demonstrieren (die direkte Überprüfung könnte mit einem Debugger erfolgen, dies würde sich jedoch eher auf die internen Datentypen von jq als auf die konzeptionellen Datentypen hinter JSON beziehen). .
$ jq -c '. []' <<< '["a", "b"]'
"ein"
"b"
$ jq -cn '"a", "b"'
"ein"
"b"
Beachten Sie, dass die Ausgabe kein Array ist (was wäre ["a", "b"]
). Die kompakte Ausgabe (die -c
Option) zeigt, dass jedes Array-Element (oder Argument für den ,
Filter) zu einem separaten Objekt in der Ausgabe wird (jedes befindet sich in einer separaten Zeile).
Ein Stream ähnelt einer JSON- Sequenz, verwendet jedoch bei der Codierung Zeilenumbrüche anstelle von RS als Ausgabetrennzeichen. Folglich wird dieser interne Typ in dieser Antwort mit dem Oberbegriff "Sequenz" bezeichnet, wobei "Stream" für die codierte Eingabe und Ausgabe reserviert ist.
Filter konstruieren
Die Schlüssel des ersten Objekts können extrahiert werden mit:
.[0] | keys_unsorted
Die Schlüssel werden im Allgemeinen in ihrer ursprünglichen Reihenfolge aufbewahrt, die genaue Reihenfolge wird jedoch nicht garantiert. Folglich müssen sie zum Indizieren der Objekte verwendet werden, um die Werte in derselben Reihenfolge zu erhalten. Dadurch wird auch verhindert, dass sich Werte in den falschen Spalten befinden, wenn einige Objekte eine andere Schlüsselreihenfolge haben.
Damit beide die Schlüssel als erste Zeile ausgeben und für die Indizierung verfügbar machen, werden sie in einer Variablen gespeichert. Die nächste Stufe der Pipeline verweist dann auf diese Variable und verwendet den Kommaoperator, um den Header dem Ausgabestream voranzustellen.
(.[0] | keys_unsorted) as $keys | $keys, ...
Der Ausdruck nach dem Komma ist ein wenig kompliziert. Der Indexoperator für ein Objekt kann eine Folge von Zeichenfolgen (z. B. "name", "value"
) annehmen und eine Folge von Eigenschaftswerten für diese Zeichenfolgen zurückgeben. $keys
ist ein Array, keine Sequenz, wird also []
angewendet, um es in eine Sequenz zu konvertieren.
$keys[]
die dann weitergegeben werden kann .[]
.[ $keys[] ]
Auch dies erzeugt eine Sequenz, sodass der Array-Konstruktor verwendet wird, um sie in ein Array zu konvertieren.
[.[ $keys[] ]]
Dieser Ausdruck soll auf ein einzelnes Objekt angewendet werden. map()
wird verwendet, um es auf alle Objekte im äußeren Array anzuwenden:
map([.[ $keys[] ]])
Zuletzt wird dies für diese Phase in eine Sequenz konvertiert, sodass jedes Element zu einer separaten Zeile in der Ausgabe wird.
map([.[ $keys[] ]])[]
Warum die Sequenz in einem Array bündeln, map
um sie nur außerhalb zu entbündeln? map
erzeugt ein Array; .[ $keys[] ]
erzeugt eine Sequenz. Das Anwenden map
auf die Sequenz von .[ $keys[] ]
würde ein Array von Wertesequenzen erzeugen. Da Sequenzen jedoch kein JSON-Typ sind, erhalten Sie stattdessen ein abgeflachtes Array, das alle Werte enthält.
["NSW","AU","state","New South Wales","AB","CA","province","Alberta","ABD","GB","council area","Aberdeenshire","AK","US","state","Alaska"]
Die Werte von jedem Objekt müssen getrennt gehalten werden, damit sie in der endgültigen Ausgabe zu getrennten Zeilen werden.
Schließlich wird die Sequenz durch den @csv
Formatierer geleitet.
Wechseln
Die Elemente können eher spät als früh getrennt werden. Anstatt den Komma-Operator zum Abrufen einer Sequenz zu verwenden (indem eine Sequenz als rechter Operand übergeben wird), kann die Header-Sequenz ( $keys
) in ein Array eingeschlossen und +
zum Anhängen des Wertearrays verwendet werden. Dies muss noch in eine Sequenz konvertiert werden, bevor es an übergeben wird @csv
.
json2csv
unter stackoverflow.com/questions/57242240/…