다음 JSON 파일이 있습니다.
{ data : [
{
"name" : "name1"
"date" : [
{
"date1" : "aaa",
"date2" : "bbb"
},
{
"date1" : "ccc",
"date2" : "ddd"
},
{
"date1" : "eee",
"date2" : "fff"
},
"var" : "ggg"
},
{
"name" : "name2"
"date" : [
{
"date1" : "hhh",
"date2" : "iii"
},
{
"date1" : "jjj",
"date2" : "kkk"
},
"var" : "lll"
}
]
}
다음 형식의 CSV 파일을 원합니다.
name, date, var
name1, aaa ccc eee, ggg
name2, hhh jjj, lll
jq만 사용해도 되나요?
답변1
JSON 문서가 제시된 텍스트의 다음 수정된 변형과 같이 올바른 형식이라고 가정합니다.
{
"data": [
{
"name": "name1",
"date": [
{
"date1": "aaa",
"date2": "bbb"
},
{
"date1": "ccc",
"date2": "ddd"
},
{
"date1": "eee",
"date2": "fff"
}
],
"var": "ggg"
},
{
"name": "name2",
"date": [
{
"date1": "hhh",
"date2": "iii"
},
{
"date1": "jjj",
"date2": "kkk"
}
],
"var": "lll"
}
]
}
그런 다음 다음을 수행할 수 있습니다.
$ jq -r '[ "name", "date", "var" ], (.data[] | [.name, ([.date[].date1] | join(" ")), .var]) | @csv' file
"name","date","var"
"name1","aaa ccc eee","ggg"
"name2","hhh jjj","lll"
이 jq
표현은 구조를 보여주기 위해 더 많은 공기를 사용합니다.
[ "name", "date", "var" ],
(
.data[] |
[
.name,
( [ .date[].date1 ] | join(" ") ),
.var
]
) |
@csv
먼저 CSV 헤더를 문자열 배열로 생성합니다. 그런 다음 최상위 배열을 반복하여 data
및 키의 값을 배열로 가져옵니다. 또한 배열에 있는 하위 키의 모든 값을 선택하고 이를 구분 기호로 공백으로 연결합니다.name
var
date1
date
data
@csv
그런 다음 출력을 위해 각 문자열을 참조하고 요소를 쉼표로 구분하는 각 요소에 대해 작성된 배열과 CSV 헤더 배열을 처리합니다 .
또 다른 변형:
box% jq -r '.data[].date |= ( [.[].date1] | join(" ") ) | [ (.data[0] | keys[]) ], (.data[]| [.[]]) | @csv' file
"date","name","var"
"name1","aaa ccc eee","ggg"
"name2","hhh jjj","lll"
이는 첫 번째 파이프라인 뒤의 표현식 부분이 다음 입력을 얻도록 데이터를 전처리합니다.
{
"data": [
{
"name": "name1",
"date": "aaa ccc eee",
"var": "ggg"
},
{
"name": "name2",
"date": "hhh jjj",
"var": "lll"
}
]
}
첫 번째 파이프라인 이후의 코드는 단순히 CSV 헤더의 키를 추출하고 키 이름을 걱정하지 않고 값을 수집합니다.
이번에도 jq
설명을 위해 표현에 약간의 공기를 넣어 삽입했습니다.
.data[].date |= ( [ .[].date1 ] | join(" ") ) |
[ (.data[0] | keys[]) ],
( .data[] | [.[]] ) |
@csv
이상해 보이지만 .data[] | [.[]]
각 요소의 모든 키 값을 포함하는 배열을 만듭니다 data
.
.[]
배열이 아닌 항목에 적용하면 keys
생성된 순서와 다른 순서로 값이 추출 될 수 있다는 우려가 있는 경우 다음을 사용할 수 있습니다.
.data[].date |= ( [ .[].date1 ] | join(" ")) |
(.data[0] | keys) as $keys |
$keys,
( .data[]| [ .[$keys[]] ] ) |
@csv
즉, 헤더 키를 변수로 가져와 $keys
이를 사용하여 CSV 헤더를 생성합니다.그리고배열의 요소에서 데이터를 추출하는 데 사용됩니다 data
. 열은 임의의 순서로 되어 있을 수 있지만 최소한 헤더와 나머지 데이터는 동일한 임의의 순서로 되어 있으므로 CSV 파서는 이름으로 열을 가져오는 데 아무런 문제가 없습니다.