← 블로그로 돌아가기

JSON 경로 찾기: JSONPath 완벽 가이드와 실용 도구

JSON 데이터에서 원하는 값의 경로를 찾고 JSONPath를 마스터하세요. 실용적인 예제와 도구를 통해 완벽히 배워봅니다.

Big JSON Team11분 소요tools
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

11 분 읽기

# JSON 경로 찾기: JSONPath 완벽 가이드와 실용 도구

복잡한 JSON 데이터에서 특정 값을 찾고 접근하는 것은 개발자의 일상입니다. JSONPath를 마스터하여 효율적으로 데이터를 다루는 방법을 배워보세요.

JSON 경로란?

JSON 경로는 JSON 데이터 구조 내에서 특정 값의 위치를 나타내는 표기법입니다.

간단한 예제

{

"user": {

"name": "홍길동",

"address": {

"city": "서울"

}

}

}

경로 표기:
  • user.name → "홍길동"
  • user.address.city → "서울"

JSONPath란?

JSONPath는 XPath와 유사한 JSON용 쿼리 언어입니다. JSON 데이터를 쿼리하고 추출할 수 있습니다.

기본 연산자

| 연산자 | 설명 | 예제 |

|-------|------|------|

| $ | 루트 객체 | $ |

| @ | 현재 객체 | @.price |

| . | 자식 접근 | $.user.name |

| [] | 배열 접근 | $[0] |

| .. | 재귀 하강 | $..price |

| | 와일드카드 | $.users[] |

| [,] | 다중 선택 | $[0,2,5] |

| [:] | 배열 슬라이스 | $[0:5] |

| ?() | 필터 | $[?(@.price < 10)] |

기본 경로 표기법

객체 접근

{

"name": "홍길동",

"age": 30,

"email": "hong@example.com"

}

경로:
  • $.name → "홍길동"
  • $.age → 30
  • $.email → "hong@example.com"

중첩 객체

{

"user": {

"profile": {

"name": "홍길동",

"contact": {

"email": "hong@example.com"

}

}

}

}

경로:
  • $.user.profile.name → "홍길동"
  • $.user.profile.contact.email → "hong@example.com"

배열 접근

{

"users": ["홍길동", "김철수", "이영희"]

}

경로:
  • $.users[0] → "홍길동"
  • $.users[1] → "김철수"
  • $.users[2] → "이영희"
  • $.users[-1] → "이영희" (마지막)

객체 배열

{

"users": [

{ "name": "홍길동", "age": 30 },

{ "name": "김철수", "age": 25 }

]

}

경로:
  • $.users[0].name → "홍길동"
  • $.users[1].age → 25
  • $.users[].name → ["홍길동", "김철수"]

고급 JSONPath 표현식

와일드카드 ()

모든 요소 선택:

{

"store": {

"book": [

{ "title": "책1", "price": 10 },

{ "title": "책2", "price": 15 }

]

}

}

경로:
  • $.store.book[].title → ["책1", "책2"]
  • $.store.book[].price → [10, 15]

재귀 하강 (..)

모든 레벨에서 검색:

{

"company": {

"department": {

"name": "개발팀",

"team": {

"name": "프론트엔드"

}

}

}

}

경로:
  • $..name → ["개발팀", "프론트엔드"]

배열 슬라이스

{

"numbers": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

}

경로:
  • $.numbers[0:3] → [0, 1, 2]
  • $.numbers[2:5] → [2, 3, 4]
  • $.numbers[-3:] → [7, 8, 9]
  • $.numbers[::2] → [0, 2, 4, 6, 8] (짝수 인덱스)

다중 선택

{

"items": ["a", "b", "c", "d", "e"]

}

경로:
  • $.items[0,2,4] → ["a", "c", "e"]
  • $.items[1,3] → ["b", "d"]

필터 표현식

{

"products": [

{ "name": "노트북", "price": 1500000, "stock": 5 },

{ "name": "마우스", "price": 30000, "stock": 50 },

{ "name": "키보드", "price": 80000, "stock": 0 }

]

}

경로:
  • $.products[?(@.price < 100000)] → 10만원 미만 제품
  • $.products[?(@.stock > 0)] → 재고 있는 제품
  • $.products[?(@.name == '마우스')] → 이름이 "마우스"인 제품

필터 연산자:
  • ==: 같음
  • !=: 다름
  • <: 작음
  • <=: 작거나 같음
  • >: 큼
  • >=: 크거나 같음
  • =~: 정규식 매치

복합 필터

{

"products": [

{ "name": "노트북", "price": 1500000, "category": "전자" },

{ "name": "마우스", "price": 30000, "category": "전자" },

{ "name": "책", "price": 15000, "category": "도서" }

]

}

경로:
  • $.products[?(@.price > 20000 && @.category == '전자')]
  • $.products[?(@.price < 50000 || @.category == '도서')]

JavaScript에서 사용하기

jsonpath 라이브러리

npm install jsonpath
기본 사용:
const jp = require('jsonpath');

const data = {

store: {

book: [

{ title: '책1', price: 10, author: '저자1' },

{ title: '책2', price: 15, author: '저자2' },

{ title: '책3', price: 8, author: '저자1' }

]

}

};

// 모든 책 제목

const titles = jp.query(data, '$.store.book[].title');

console.log(titles); // ['책1', '책2', '책3']

// 가격이 10보다 작은 책

const cheap = jp.query(data, '$.store.book[?(@.price < 10)]');

console.log(cheap); // [{ title: '책3', price: 8, author: '저자1' }]

// 특정 저자의 책

const byAuthor = jp.query(data, "$.store.book[?(@.author == '저자1')]");

console.log(byAuthor);

경로 가져오기:
const paths = jp.paths(data, '$.store.book[].title');

console.log(paths);

// [

// ['$', 'store', 'book', 0, 'title'],

// ['$', 'store', 'book', 1, 'title'],

// ['$', 'store', 'book', 2, 'title']

// ]

경로 문자열로:
paths.forEach(path => {

console.log(jp.stringify(path));

});

// $['store']['book'][0]['title']

// $['store']['book'][1]['title']

// $['store']['book'][2]['title']

값 설정:
jp.value(data, '$.store.book[0].price', 12);

console.log(data.store.book[0].price); // 12

노드 정보:
const nodes = jp.nodes(data, '$.store.book[].price');

nodes.forEach(node => {

console.log('경로:', node.path);

console.log('값:', node.value);

});

lodash/get (간단한 경로)

npm install lodash
const _ = require('lodash');

const data = {

user: {

profile: {

name: '홍길동'

}

}

};

// 안전한 접근

const name = _.get(data, 'user.profile.name');

console.log(name); // '홍길동'

// 기본값 제공

const age = _.get(data, 'user.profile.age', 0);

console.log(age); // 0

// 배열 경로

const items = {

users: [

{ name: '홍길동' },

{ name: '김철수' }

]

};

const firstName = _.get(items, 'users[0].name');

console.log(firstName); // '홍길동'

Python에서 사용하기

jsonpath-ng

pip install jsonpath-ng
from jsonpath_ng import parse

data = {

'store': {

'book': [

{'title': '책1', 'price': 10},

{'title': '책2', 'price': 15}

]

}

}

# 경로 파싱

jsonpath_expr = parse('$.store.book[].title')

# 값 찾기

matches = jsonpath_expr.find(data)

for match in matches:

print(f'경로: {match.full_path}')

print(f'값: {match.value}')

# 값만 추출

titles = [match.value for match in matches]

print(titles) # ['책1', '책2']

필터 사용:
from jsonpath_ng.ext import parse

data = {

'products': [

{'name': '노트북', 'price': 1500000},

{'name': '마우스', 'price': 30000}

]

}

# 가격이 100000보다 작은 제품

jsonpath_expr = parse('$.products[?(@.price < 100000)]')

matches = jsonpath_expr.find(data)

for match in matches:

print(match.value)

실용 예제

API 응답에서 데이터 추출

const jp = require('jsonpath');

const apiResponse = {

status: 'success',

data: {

users: [

{

id: 1,

name: '홍길동',

posts: [

{ id: 101, title: '첫 게시물', likes: 10 },

{ id: 102, title: '두번째', likes: 25 }

]

},

{

id: 2,

name: '김철수',

posts: [

{ id: 201, title: '안녕하세요', likes: 5 }

]

}

]

}

};

// 모든 사용자 이름

const names = jp.query(apiResponse, '$.data.users[].name');

console.log('사용자:', names);

// 모든 게시물 제목

const titles = jp.query(apiResponse, '$..posts[].title');

console.log('게시물:', titles);

// 좋아요 10개 이상인 게시물

const popular = jp.query(apiResponse, '$..posts[?(@.likes >= 10)]');

console.log('인기 게시물:', popular);

// 특정 사용자의 게시물

const userPosts = jp.query(

apiResponse,

"$.data.users[?(@.name == '홍길동')].posts[]"

);

console.log('홍길동의 게시물:', userPosts);

설정 파일에서 값 찾기

const config = {

app: {

name: 'MyApp',

version: '1.0.0',

environments: {

development: {

api: 'http://localhost:3000',

debug: true

},

production: {

api: 'https://api.example.com',

debug: false

}

}

},

features: {

authentication: { enabled: true },

notifications: { enabled: false }

}

};

// 모든 API URL

const apis = jp.query(config, '$..api');

console.log('APIs:', apis);

// 활성화된 기능

const enabledFeatures = jp.query(

config,

'$.features[?(@.enabled == true)]'

);

console.log('활성화된 기능:', enabledFeatures);

중첩된 데이터 변환

const data = {

company: {

departments: [

{

name: '개발',

employees: [

{ name: '홍길동', salary: 50000 },

{ name: '김철수', salary: 45000 }

]

},

{

name: '디자인',

employees: [

{ name: '이영희', salary: 48000 }

]

}

]

}

};

// 모든 직원 이름

const employees = jp.query(data, '$..employees[].name');

console.log('직원:', employees);

// 급여 합계

const salaries = jp.query(data, '$..employees[].salary');

const total = salaries.reduce((sum, sal) => sum + sal, 0);

console.log('총 급여:', total);

// 부서별 직원 수

const depts = jp.query(data, '$.company.departments[]');

depts.forEach(dept => {

console.log(${dept.name}: ${dept.employees.length}명);

});

온라인 JSONPath 도구

1. JSON Simplify

JSON Simplify - 한국어 지원 기능:
  • JSONPath 쿼리
  • 경로 자동 생성
  • 시각적 트리 뷰
  • 값 복사

사용법:
  • JSON 데이터 입력
  • 원하는 값 클릭
  • 경로 자동 표시
  • 2. JSONPath Online Evaluator

    jsonpath.com 기능:
    • JSONPath 테스트
    • 예제 제공
    • 문법 참조

    3. JSONPath Finder

    jsonpathfinder.com 기능:
    • 시각적 경로 찾기
    • 드래그 앤 드롭
    • 경로 복사

    도구별 JSONPath 구현 차이

    구현별 지원 기능

    | 기능 | Goessner | jsonpath-ng | jayway |

    |------|----------|-------------|--------|

    | 기본 경로 | ✅ | ✅ | ✅ |

    | 재귀 하강 | ✅ | ✅ | ✅ |

    | 필터 | ✅ | ✅ | ✅ |

    | 스크립트 | ❌ | ❌ | ✅ |

    | 함수 | ❌ | ❌ | ✅ |

    주의사항

    일부 고급 기능은 구현마다 다를 수 있습니다. 사용 전에 문서를 확인하세요.

    성능 고려사항

    1. 재귀 하강 최소화

    // 느림
    

    jp.query(data, '$..name');

    // 빠름 (정확한 경로)

    jp.query(data, '$.users[].name');

    2. 필터 최적화

    // 느림
    

    jp.query(data, '$..products[?(@.price < 100)]');

    // 빠름

    jp.query(data, '$.products[?(@.price < 100)]');

    3. 캐싱

    // 경로 표현식 재사용
    

    const expr = jp.compile('$.users[].name');

    // 여러 번 사용

    const names1 = expr.query(data1);

    const names2 = expr.query(data2);

    모범 사례

    1. 명확한 경로 사용

    // 좋음
    

    '$.users[0].profile.name'

    // 나쁨 (너무 모호함)

    '$..name'

    2. 안전한 접근

    // 존재하지 않을 수 있는 경로
    

    const result = jp.query(data, '$.user.profile.name');

    const name = result.length > 0 ? result[0] : '기본값';

    3. 타입 검증

    const prices = jp.query(data, '$.products[*].price');
    

    const validPrices = prices.filter(p => typeof p === 'number');

    4. 문서화

    // 복잡한 쿼리에 주석 추가
    

    const query = '$.store.book[?(@.price < 10 && @.category == "fiction")]';

    // 10달러 미만 소설책 찾기

    결론

    JSONPath는 복잡한 JSON 데이터를 쿼리하는 강력한 도구입니다. 기본 경로부터 고급 필터까지 마스터하면 데이터 처리가 훨씬 쉬워집니다.

    핵심 요약:
    • ✅ 점 표기법으로 객체 접근
    • ✅ 대괄호로 배열 접근
    • ✅ 필터로 조건부 선택
    • ✅ 재귀 하강으로 깊은 검색
    • ✅ 적절한 라이브러리 선택

    지금 바로 JSON Simplify에서 JSON 경로를 찾아보세요!

    Share:

    관련 글

    Read in English