your programing

jq를 사용하여 임의의 단순 JSON을 CSV로 변환하려면 어떻게 해야 합니까?

lovepro 2023. 4. 2. 12:38
반응형

jq를 사용하여 임의의 단순 JSON을 CSV로 변환하려면 어떻게 해야 합니까?

jq를 사용하여 얕은 개체의 배열을 임의의 JSON 인코딩을 CSV로 변환하려면 어떻게 해야 합니까?

이 사이트에는 필드를 하드 코드화하는 특정 데이터 모델을 다루는 Q&A가 많이 있지만, 스칼라 속성을 가진 오브젝트 배열이라는 제한만 있으면 이 질문에 대한 답변은 유효합니다(이러한 질문을 평평하게 하는 것은 다른 질문이기 때문에).결과에는 필드 이름을 나타내는 헤더 행이 포함되어 있어야 합니다.첫 번째 객체의 필드 순서를 유지하는 답변이 우선되지만 필수 사항은 아닙니다.결과는 모든 셀을 이중 따옴표로 둘러싸거나 인용이 필요한 셀만 포함할 수 있습니다(예: 'a, b').

  1. 입력:

    [
        {"code": "NSW", "name": "New South Wales", "level":"state", "country": "AU"},
        {"code": "AB", "name": "Alberta", "level":"province", "country": "CA"},
        {"code": "ABD", "name": "Aberdeenshire", "level":"council area", "country": "GB"},
        {"code": "AK", "name": "Alaska", "level":"state", "country": "US"}
    ]
    

    가능한 출력:

    code,name,level,country
    NSW,New South Wales,state,AU
    AB,Alberta,province,CA
    ABD,Aberdeenshire,council area,GB
    AK,Alaska,state,US
    

    가능한 출력:

    "code","name","level","country"
    "NSW","New South Wales","state","AU"
    "AB","Alberta","province","CA"
    "ABD","Aberdeenshire","council area","GB"
    "AK","Alaska","state","US"
    
  2. 입력:

    [
        {"name": "bang", "value": "!", "level": 0},
        {"name": "letters", "value": "a,b,c", "level": 0},
        {"name": "letters", "value": "x,y,z", "level": 1},
        {"name": "bang", "value": "\"!\"", "level": 1}
    ]
    

    가능한 출력:

    name,value,level
    bang,!,0
    letters,"a,b,c",0
    letters,"x,y,z",1
    bang,"""!""",0
    

    가능한 출력:

    "name","value","level"
    "bang","!","0"
    "letters","a,b,c","0"
    "letters","x,y,z","1"
    "bang","""!""","1"
    

먼저 객체 배열 입력에 포함된 모든 다른 객체 속성 이름을 포함하는 배열을 가져옵니다.CSV의 열은 다음과 같습니다.

(map(keys) | add | unique) as $cols

그런 다음 개체 배열 입력의 각 개체에 대해 얻은 열 이름을 개체 내의 해당 속성에 매핑합니다.CSV 행이 됩니다.

map(. as $row | $cols | map($row[.])) as $rows

열 이름을 행 그 행 을 CSV로 합니다.@csv필터링을 실시합니다.

$cols, $rows[] | @csv

이젠 다 함께. 말고 꼭 하세요.-r" " " " " " 플래그

jq -r '(map(keys) | add | unique) as $cols | map(. as $row | $cols | map($row[.])) as $rows | $cols, $rows[] | @csv'

스키니

jq -r '(.[0] | keys_unsorted) as $keys | $keys, map([.[ $keys[] ]])[] | @csv'

또는 다음과 같이 입력합니다.

jq -r '(.[0] | keys_unsorted) as $keys | ([$keys] + map([.[ $keys[] ]])) [] | @csv'

상세 정보

따로

jq는 스트림 지향이기 때문에 상세 설명은 까다롭습니다.즉, 단일 값이 아닌 일련의 JSON 데이터로 동작합니다.입력 JSON 스트림은 필터를 통과하는 내부 유형으로 변환된 다음 프로그램 끝에 출력 스트림으로 인코딩됩니다.내부 유형은 JSON에 의해 모델링되지 않았으며 명명된 유형으로 존재하지 않습니다.맨지수, , 맨지수, 맨지수, 맨지수, 맨지수, 맨지수, 맨지수, 맨지수, 맨지수, 맨지수..[] 연산자디버거를 할 수 , 는 JSON 유형에 입니다.

$ jq - c ' . [ ]' < < < < ' < " " a , " b " ]
"a""b"$ jq - cn "a", "b""a""b"

출력은 어레이가 아니라는 점에 주의:["a", "b"]콤팩트 출력(-coption)는 각 어레이 요소(또는 에 대한 인수)를 나타냅니다.,filter)는 출력에서 개별 객체가 됩니다(각 객체는 다른 행에 있습니다).

스트림은 JSON-seq와 비슷하지만 인코딩 시 출력 구분자로 RS가 아닌 새 행을 사용합니다.따라서 이 내부 유형은 이 응답에서 일반적인 용어 "sequence"로 참조되며 "stream"은 인코딩된 입력 및 출력용으로 예약됩니다.

필터 구성

첫 번째 객체의 키는 다음과 같이 추출할 수 있습니다.

.[0] | keys_unsorted

일반적으로 키는 원래 순서대로 유지되지만 정확한 순서를 유지하는 것은 보장되지 않습니다.따라서 동일한 순서로 값을 가져오려면 개체를 인덱싱하는 데 사용해야 합니다.이렇게 하면 일부 개체의 키 순서가 다른 경우에도 값이 잘못된 열에 들어가는 것을 방지할 수 있습니다.

두 키 모두 첫 번째 행으로 출력하고 인덱싱에 사용할 수 있도록 변수에 저장됩니다.파이프라인의 다음 단계는 이 변수를 참조하고 쉼표 연산자를 사용하여 출력 스트림에 머리글을 추가합니다.

(.[0] | keys_unsorted) as $keys | $keys, ...

쉼표 뒤에 나오는 표현은 조금 복잡해요.오브젝트의 인덱스 연산자는 일련의 문자열(예:"name", "value")는 이러한 문자열의 속성 값 시퀀스를 반환합니다. $keys배열이지 시퀀스가 아니기 때문에[]적용되어 시퀀스로 변환됩니다.

$keys[]

다음으로 전달될 수 있습니다..[]

.[ $keys[] ]

이것 역시 시퀀스를 생성하기 때문에 배열 생성자는 이를 배열로 변환하는 데 사용됩니다.

[.[ $keys[] ]]

이 식은 단일 개체에 적용됩니다. map()외부 배열의 모든 객체에 적용하기 위해 사용됩니다.

map([.[ $keys[] ]])

마지막으로 이 단계에서는 시퀀스로 변환되어 각 항목이 출력에서 개별 행이 됩니다.

map([.[ $keys[] ]])[]

시퀀스를 내부 어레이에 번들하는 이유map그걸 밖에서 풀기만 하면 되는 거야? map어레이를 생성합니다..[ $keys[] ]그럼 시퀀스가 생성됩니다.신청중map로부터의 순서로.[ $keys[] ]값의 배열이 생성되지만 시퀀스는 JSON 유형이 아니기 때문에 모든 값이 포함된 평탄한 배열이 됩니다.

["NSW","AU","state","New South Wales","AB","CA","province","Alberta","ABD","GB","council area","Aberdeenshire","AK","US","state","Alaska"]

각 객체의 값은 최종 출력에서 개별 행이 되도록 별도로 유지해야 합니다.

는 지막으로 finally finally finally finally finally finally finally finally finally finally finally 를 통과합니다.@csv포맷을 합니다.

교대하는

물품은 일찍이 아니라 늦게 분리될 수 있습니다.), 를 취득합니다.$keys로 묶을 수 또, )는 배열로 수 있습니다.+값 배열을 추가하는 데 사용됩니다..@csv.

다음 필터는 모든 값이 문자열로 변환된다는 점에서 약간 다릅니다.(jq 1.5+)

# For an array of many objects
jq -f filter.jq [file]

# For many objects (not within array)
jq -s -f filter.jq [file]

터::filter.jq

def tocsv:
    (map(keys)
        |add
        |unique
        |sort
    ) as $cols
    |map(. as $row
        |$cols
        |map($row[.]|tostring)
    ) as $rows
    |$cols,$rows[]
    | @csv;

tocsv
$cat test.json
[
    {"code": "NSW", "name": "New South Wales", "level":"state", "country": "AU"},
    {"code": "AB", "name": "Alberta", "level":"province", "country": "CA"},
    {"code": "ABD", "name": "Aberdeenshire", "level":"council area", "country": "GB"},
    {"code": "AK", "name": "Alaska", "level":"state", "country": "US"}
]


$ jq -r '["Code", "Name", "Level", "Country"], (.[] | [.code, .name, .level, .country]) | @tsv ' test.json
Code    Name    Level   Country
NSW New South Wales state   AU
AB  Alberta province    CA
ABD Aberdeenshire   council area    GB
AK  Alaska  state   US


$ jq -r '["Code", "Name", "Level", "Country"], (.[] | [.code, .name, .level, .country]) | @csv ' test.json
"Code","Name","Level","Country"
"NSW","New South Wales","state","AU"
"AB","Alberta","province","CA"
"ABD","Aberdeenshire","council area","GB"
"AK","Alaska","state","US"

오브젝트 또는 어레이의 배열을 헤더가 있는 csv로 출력하는 함수를 만들었습니다.열은 머리글 순서대로 표시됩니다.

def to_csv($headers):
    def _object_to_csv:
        ($headers | @csv),
        (.[] | [.[$headers[]]] | @csv);
    def _array_to_csv:
        ($headers | @csv),
        (.[][:$headers|length] | @csv);
    if .[0]|type == "object"
        then _object_to_csv
        else _array_to_csv
    end;

따라서 다음과 같이 사용할 수 있습니다.

to_csv([ "code", "name", "level", "country" ])

Santiago의 이 프로그램 변형도 안전하지만 첫 번째 개체의 키 이름이 첫 번째 열 헤더로 사용되는 것은 해당 개체에 나타나는 순서와 동일합니다.

def tocsv:
  if length == 0 then empty
  else
    (.[0] | keys_unsorted) as $firstkeys
    | (map(keys) | add | unique) as $allkeys
    | ($firstkeys + ($allkeys - $firstkeys)) as $cols
    | ($cols, (.[] as $row | $cols | map($row[.])))
    | @csv
  end ;

tocsv

다른 Unix 툴을 사용할 의향이 있는 경우,in2csv 삭제:

in2csv example.json

샘플 데이터 사용:

> in2csv example.json
code,name,level,country
NSW,New South Wales,state,AU
AB,Alberta,province,CA
ABD,Aberdeenshire,council area,GB
AK,Alaska,state,US 

접속하는 .jq:

cat example.json | in2csv -f json -

간단한 방법은 문자열 연결을 사용하는 것입니다.입력이 적절한 어레이인 경우:

# filename.txt
[
  {"field1":"value1", "field2":"value2"},
  {"field1":"value1", "field2":"value2"},
  {"field1":"value1", "field2":"value2"}
]

해서 를 붙입니다..[]:

cat filename.txt | jq -r '.[] | .field1 + ", " + .field2'

또는 한 줄 한 줄 객체일 경우:

# filename.txt
{"field1":"value1", "field2":"value2"}
{"field1":"value1", "field2":"value2"}
{"field1":"value1", "field2":"value2"}

다음 작업을 수행합니다.

cat filename.txt | jq -r '.field1 + ", " + .field2'

언급URL : https://stackoverflow.com/questions/32960857/how-to-convert-arbitrary-simple-json-to-csv-using-jq

반응형