次のtocsv
およびfromcsv
関数は、ヘッダーに関する要件(6)に関する1つの複雑さを除いて、述べられた問題の解決策を提供します。基本的に、この要件は、行列転置ステップを追加することにより、ここで提供される関数を使用して満たすことができます。
転置ステップが追加されているかどうかに関係なく、ここで採用されているアプローチの利点は、JSONキーまたは値に制限がないことです。特に、ピリオド(ドット)、改行、NUL文字が含まれている場合があります。
この例では、オブジェクトの配列が示されていますが、実際には、有効なJSONドキュメントの任意のストリームをtocsv
への入力として使用できます。; jqの魔法のおかげで、元のストリームはfromcsv
によって再作成されます (エンティティごとの平等という意味で)
もちろん、CSV規格がないため、tocsv
で作成されたCSV 機能がすべてのCSVプロセッサで理解されるとは限りません。特に、tocsv
に注意してください ここで定義された関数は、JSON文字列またはキー名に埋め込まれた改行を2文字の文字列「\ n」(つまり、リテラルのバックスラッシュの後に文字「n」が続く)にマップします。逆演算は、「ラウンドトリップ」を満たすために逆変換を実行します。要件。
(tail
の使用 プレゼンテーションを単純化するだけです。ソリューションを変更して、jqのみにするのは簡単です。)
CSVは、(a)フィールドが引用符で囲まれ、(b)フィールド内の二重引用符が二重になっている限り、任意の値をフィールドに含めることができるという前提で生成されます。
「ラウンドトリップ」をサポートする一般的なソリューションは、やや複雑になります。ここに示すソリューションが予想よりも複雑である主な理由は、3番目の列が追加されているためです。これは、整数と整数値の文字列を簡単に区別できるようにするためですが、主にサイズ1とサイズを簡単に区別できるためです。 -jqの--stream
によって生成された2つの配列 オプション。言うまでもなく、これらの問題に対処する方法は他にもあります。 jqへの呼び出しの数も減らすことができます。
このソリューションは、テストケースを伝える際のラウンドトリップ要件をチェックするテストスクリプトとして提示されます。
#!/bin/bash
function json {
cat<<EOF
[
{
"a": 1,
"b": [
1,
2,
"1"
],
"c": "d\",ef",
"embed\"ed": "quote",
"null": null,
"string": "null",
"control characters": "a\u0000c",
"newline": "a\nb"
},
{
"x": 1
}
]
EOF
}
function tocsv {
jq -ncr --stream '
(["path", "value", "stringp"],
(inputs | . + [.[1]|type=="string"]))
| map( tostring|gsub("\"";"\"\"") | gsub("\n"; "\\n"))
| "\"\(.[0])\",\"\(.[1])\",\(.[2])"
'
}
function fromcsv {
tail -n +2 | # first duplicate backslashes and deduplicate double-quotes
jq -rR '"[\(gsub("\\\\";"\\\\") | gsub("\"\"";"\\\"") ) ]"' |
jq -c '.[2] as $s
| .[0] |= fromjson
| .[1] |= if $s then . else fromjson end
| if $s == null then [.[0]] else .[:-1] end
# handle newlines
| map(if type == "string" then gsub("\\\\n";"\n") else . end)' |
jq -n 'fromstream(inputs)'
}
# Check the roundtrip:
json | tocsv | fromcsv | jq -s '.[0] == .[1]' - <(json)
これがjson | tocsv
、SOが文字通りのNULを許可していないように見えることを除いて、私はそれを\0
に置き換えました :
"path","value",stringp
"[0,""a""]","1",false
"[0,""b"",0]","1",false
"[0,""b"",1]","2",false
"[0,""b"",2]","1",true
"[0,""b"",2]","false",null
"[0,""c""]","d"",ef",true
"[0,""embed\""ed""]","quote",true
"[0,""null""]","null",false
"[0,""string""]","null",true
"[0,""control characters""]","a\0c",true
"[0,""newline""]","a\nb",true
"[0,""newline""]","false",null
"[1,""x""]","1",false
"[1,""x""]","false",null
"[1]","false",null