CKA를 준비해보자 37일차 - jsonpath

0

CKA

목록 보기
37/43

YAML

yaml은 json, xml과 같이 config data를 표현하기 위한 하나의 형식이다.

  • key value pair
Fruit: Apple
Vegetable: Carrot
Liquid: Water
Meat: Chiken
  • array/list
Fruits:
- Orange
- Apple
- banana

Vegetables:
- Carrot
- Tomato
  • Dictionary/Map
Banana:
  Calories: 105
  Fat: 0.4g
  Carbs: 27g

Grapes:
  Fat: 0.3g
  Carbs: 16g

indentation에 있는 것을 조심하자. indentation이 다르면 상하 계층관계를 나누기 때문이다. 여기서는 Banana가 상위이고, Calories, Fat, Carbs가 하위 자식이다.

  • dictionary list
Fruits:
  - Banana:
      Calories: 105
      Fat: 0.4g
      Carbs: 27g
  - Grape:
      Calories: 62
      Fat: 0.3g
      Carbs: 16g

dictionary는 unordered이지만, list는 ordered이다.

Banana:
  Calories: 105
  Fat: 0.4g
  Carbs: 27g
Banana:
  Calories: 105
  Carbs: 27g
  Fat: 0.4g

위 두 Banana는 서로 같은 Banana이다. dictionary는 순서가 무의미 하기 때문이다.

그러나, 다음의 두 Fruits는 서로 다르다.

Fruits:
- Orange
- Apple
- banana
```yaml
Fruits:
- Orange
- banana
- Apple

list는 순서가 유의미한 ordered이기 때문이다

JSON path

json path는 json이나 yaml으로 된 format에서 json query로 데이터를 추출하는 방법이다.

가령 다음과 같은 json 파일이 있다고 하자.

{
    "car": {
        "color": "blue",
        "price": "$20,000"
    }
}

위 json 파일에서 json path로 query를 날리는 것이다.

car

이렇게 query를 보내면

{
    "color": "blue",
    "price": "$20,000"
}

다음의 결과가 나오는 것이다.

만약 여기서, carcolor를 추출하고 싶다면 다음과 같이 쓰면 된다.

car.color

결과는 예상하듯이 다음과 같다.

"blue"

그런데, 실제로는 위와 같이 query를 보내면 실패하는데, 이는 json의 특성상 {}로 처음에 감싸지기 때문이다.

{
    ...
}

즉 모든 json file들은 위와 같이 {}으로 시작한다. 이를 root element라고 한다. 이 root element를 표현해주어야 하는데, $으로 표현할 수 있다. 따라서, 위의 json query들을 다음과 같이 정리할 수 있다.

$.car
$.car.color

따라서, 반드시 $으로 시작한다는 사실을 잊지 말도록 하자.

또한, json path query의 결과는 모두 []로 감싸져서 나온다. 따라서 최종 결과는 다음과 같이 정리할 수 있다.

$.car
[
    {
        "color": "blue",
        "price": "$20,000"
    }
]
$.car.color
[
    "blue"
]

[]로 결과들이 감싸진다는 사실을 잊지말도록 하자.

다음은 json의 list일 때 어떻게 query를 보낼 수 있는 지 알아보자.

[
    "car",
    "bus",
    "truck",
    "bike"
]

list이기 때문에 0부터 시작해서 원소 갯수만큼 인덱싱을 할 수 있다. 추가적으로 []역시도 root element이기 때문에 []로 감싸야한다.

  • query
$[0]
  • result
["car"]

결과는 무조건 []안에 넣어진다는 사실을 잊지말자.

다음과 같이 여러개도 가져올 수 있다.

  • query
$[0, 3]
  • result
["car", "bike"]

다음은 복합 구조로, dictionary과 list가 합쳐진 구조이다.

{
    "car": {
        "color": "blue",
        "price": "$20,000",
        "wheels": [
            {
                "model": "X345ERT",
                "location": "front-right"
            },
            {
                "model": "X345GRX",
                "location": "front-left"
            },
            {
                "model": "X236DEM",
                "location": "rear-right"
            },
            {
                "model": "X987XMV",
                "location": "rear-right"
            }
        ]
    }
}

여기서 두번째 wheelsmodel 명을 가져온다고 하자. 다음과 같이 query를 쓸 수 있다.

  • query
$.car.wheels[1].model
  • result
X345GRX

json path에서 특정 조건을 설정할 수도 있다.

[
    12,
    43,
    23,
    12,
    56,
    43,
    93,
    32,
    45,
    63,
    27,
    8,
    78
]

여기서 40보다 큰 값만 가져오고 싶을 때 다음과 같이 쓸 수 있다.

  • query
$[?( @ > 40 )]

해석하자면 다음과 같다.

  1. $: root element
  2. []: list 중
  3. ?(): 조건 문
  4. @: 각 element 순회

?()조건문 안에 @로 각 element들의 조건 연산을 실행하는 것이다. 결과는 다음과 같다.

  • result
[
    43,
    56,
    43,
    93,
    45,
    63,
    78
]

==말고도 다음의 연산들이 있다.

@ == 40
@ in [40,43,45]
@ != 40
@ nin [40,43,45]

ninnot in이다.

다시 해당 예제로 돌아와보자.

{
    "car": {
        "color": "blue",
        "price": "$20,000",
        "wheels": [
            {
                "model": "X345ERT",
                "location": "front-right"
            },
            {
                "model": "X345GRX",
                "location": "front-left"
            },
            {
                "model": "X236DEM",
                "location": "rear-right"
            },
            {
                "model": "X987XMV",
                "location": "rear-right"
            }
        ]
    }
}

여기서 wheels 중에 locationrear-right인 model만 가져오고 싶다고 하자. 다음과 같이 쓸 수 있다.

  • query
$.car.wheels[?( @.location == "rear-right" )].model

결과는 다음과 같다.

  • result
"X236DEM"

응용해서 list의 모든 element를 순회할 때는 [?(@)]만 써도 된다. 그러면 모든 element를 순회한다.

이제 위에서 배운 json path query를 써보도록 하자. query를 사용하기 위해서는 jpath를 사용하면 된다.

  • q1.json
{
    "property1": "value1",
    "property2": "value2"
}

다음의 q1.json 파일에서 property1의 data를 가져오고 싶다면 다음과 같이 쓸 수 있다.

cat ./q1.json  | jpath $.property1

결과는 다음과 같다.

[
  "value1"
]

cat ./q11.json | jpath $.prizes[?(@)].laureates[?( @.id == "914" )]

JSON path - wildcard

다음의 data가 있다고 하자.

  • data.json
{
    "car": {
        "color": "blue",
        "price": "$20,000"
    },
    "bus": {
        "color": "white",
        "price": "$120,000"
    }
}

다음의 data에서 carcolor를 얻는 방법은 다음과 같다.

  • query
$.car.color

결과는 다음과 같다.

  • result.json
["blue"]

그런데, car뿐만 아니라, bus도 얻고 싶다면 어떻게해야할까?? 더 나아가서 몇 개의 key가 있는 지는 모르겠지만 각 key에 대한 color를 얻고 싶다면 어떻게 해야할까?? 이를 위해 사용하는 것이 바로 wildcard이다.

$.*.color

다음과 같이 *로 wildcard를 사용하면 각 key에 대한 color들을 가져올 수 있다. 결과는 다음과 같다.

  • result.json
["blue", "white"]

wildcard는 위와 같이 json file에서 각 key에 대한 순회도 가능하지만, json file이 list일 때도 모든 요소에 대해서 순회가 가능하다.

  • data.json
[
    {
        "model": "X345ERT",
        "location": "front-right"
    },
    {
        "model": "X345GRX",
        "location": "front-left"
    },
    {
        "model": "X236DEM",
        "location": "rear-right"
    },
    {
        "model": "X987XMV",
        "location": "rear-right"
    }
]        

위 data에서 각 list 요소에 대한 model property를 얻어보도록 하자. 다음과 같이 쓸 수 있다.

  • query
$.*.model

list에 *을 쓰는 것은 list의 모든 item을 순회한다는 의미이다.

  • result.json
["X345ERT", "X345GRX", "X236DEM", "X987XMV"]

다음의 데이터는 json key와 list가 혼재되어 있는 데이터이다.

  • data.json
{
    "car": {
        "color": "blue",
        "price": "$20,000",
        "wheels": [
            {
                "model": "X345ERT",
            },
            {
                "model": "X345GRX",
            }
        ]
    },
    "bus": {
        "color": "white",
        "price": "$120,000",
        "wheels": [
            {
                "model": "X236DEM",
            },
            {
                "model": "X987XMV",
            }
        ]
    }
}

모든 model명을 얻고 싶다면 다음과 같이 쓸 수 있다.

  • query
$.*.wheels[*].model
  • result.json
[
    "X345ERT", "X345GRX","X236DEM","X987XMV"
]

JSON path - lists

json path에서 list에 대한 slice연산도 가능하다.

  • data.json
[
    "Apple",
    "Google",
    "Microsoft",
    "Amazon",
    "Facebook",
    "Coca-Cola",
    "Samsung",
    "Disney",
    "Toyota",
    "McDonald's"
]

다음의 경우에 Apple, Google, Microsoft를 얻고 싶다면 다음과 같이 쓸 수 있다.

  • query
$[0:3]

start~end로 end는 포함하지 않는다.

  • result
[
    "Apple",
    "Google",
    "Microsoft"
]

거꾸로 인덱싱하는 것도 가능하다. -1부터 시작해서 인덱스하면 된다. 정리하면 다음과 같다.

  • data.json
[
    "Apple",     ... 0, -10
    "Google",    ... 1, -9
    "Microsoft", ... 2, -8
    "Amazon",    ... 3, -7
    "Facebook",  ... 4, -6
    "Coca-Cola", ... 5, -5
    "Samsung",   ... 6, -4
    "Disney",    ... 7, -3
    "Toyota",    ... 8, -2
    "McDonald's" ... 9, -1
]

따라서, 다음과 같이 인덱싱도 가능하다.

  • query
$[-3:]
  • result
[
    "Disney",
    "Toyota",
    "McDonald's"
]

참고로 -연산은 잘 안될수도 있으니 다음과 같이 ''을 감싸줘서 실행하는 것이 좋다.

jpath '$[-4:]'

0개의 댓글