중첩 JSON 평탄화 방법: 키 합치는 규칙

깊게 중첩된 JSON 객체를 엑셀이나 CSV로 옮기려면, 여러 단계로 감싸인 계층 구조를 하나의 표에 담을 수 있는 1차원 키-값 구조로 바꿔야 합니다. 이 변환을 JSON 평탄화(Flatten)라고 부르고, 반대로 1차원 구조를 원래의 중첩 객체로 되돌리는 과정을 구조화(Unflatten)라고 부릅니다. 두 변환 모두 정해진 규칙에 따라 기계적으로 동작하는 계산이므로, 규칙만 알면 도구 없이도 손으로 재현할 수 있습니다.
요약 ① 중첩된 객체의 키는 "상위키+구분자+하위키" 형태로 합쳐져 1차원 구조가 됩니다. ② 배열(Array)은 객체가 아니므로 평탄화 대상에서 제외되고, 원본 그대로 값이 유지됩니다. ③ 구분자로 고른 문자가 원래 키 안에 이미 들어있으면, Unflatten 시 그 키가 의도치 않게 더 쪼개집니다.
중첩 JSON을 표로 옮기려 할 때 생기는 문제
API 응답이나 설정 파일은 흔히 객체 안에 객체가 또 들어있는 구조입니다. 예를 들어 {"user": {"name": "김철수", "address": {"city": "서울"}}}처럼 사용자 정보 안에 주소 정보가 한 번 더 감싸여 있는 식입니다.
이런 구조를 그대로 엑셀이나 CSV로 옮기면 문제가 생깁니다. 표는 한 셀에 하나의 값만 담을 수 있는데, address처럼 값이 통째로 객체인 항목을 넣으면 열이 제대로 만들어지지 않거나 값이 깨져 보입니다.
그래서 address.city처럼 상위 키와 하위 키를 하나의 열 이름으로 합친 1차원 구조가 필요합니다. 이 변환을 매번 손으로 다시 조합하지 않고 정확한 규칙으로 처리하려는 것이 평탄화입니다.
도구 없이 손으로 변환하는 규칙
Flatten과 Unflatten은 각각 정해진 재귀 규칙 하나로 동작합니다. 규칙만 따라가면 작은 JSON은 직접 손으로도 변환할 수 있습니다.
평탄화(Flatten) 규칙
어떤 키의 값이 순수 객체(배열이 아니고 null도 아닌 {} 형태)이면, 그 안으로 들어가 하위 키들을 각각 "상위키+구분자+하위키"라는 새 이름으로 최상위로 끌어올립니다. 값이 객체가 아니면(배열 포함) 원래 키 그대로 결과에 씁니다.
다음 JSON을 점(.) 구분자로 평탄화한다고 하겠습니다.
{"user": {"name": "김철수", "address": {"city": "서울"}}, "tags": ["a", "b"]}
user는 객체이므로 안으로 들어갑니다. user.name은 "김철수", user.address는 다시 객체이므로 한 번 더 들어가 user.address.city는 "서울"이 됩니다. tags는 배열이라 객체가 아니므로 그대로 유지됩니다.
{"user.name": "김철수", "user.address.city": "서울", "tags": ["a", "b"]}
구조화(Unflatten) 규칙
반대 방향은 각 키를 구분자로 쪼갠 뒤, 그 조각들을 순서대로 따라가며 중첩 객체를 다시 만드는 과정입니다. 키를 구분자 기준으로 나눈 조각을 앞에서부터 하나씩 따라가면서 없는 단계는 새로 만들고, 마지막 조각에 원래 값을 넣습니다.
위에서 만든 평탄 데이터를 다시 구조화하면, user.address.city는 user, address, city 세 조각으로 쪼개져 user 객체 아래 address 객체를 만들고 그 아래 city: "서울"을 넣습니다. user.name도 같은 user 객체 아래 합류해 원래의 중첩 구조가 그대로 복원됩니다.
저희 도구로 확인하기.
입력한 JSON은 서버로 전송되지 않고 브라우저 안에서만 평탄화·구조화 변환됩니다.

헷갈리기 쉬운 지점 — 배열 처리와 구분자 선택
두 가지가 특히 자주 헷갈립니다. 하나는 배열이 있을 때 결과가 예상과 다르게 나오는 것이고, 다른 하나는 구분자 선택 때문에 Unflatten 결과가 원본과 달라지는 것입니다.
배열이 있을 때 생기는 결과
먼저 배열입니다. {"users": [{"name": "김철수"}, {"name": "이영희"}]}처럼 배열 안에 객체가 들어있어도, users의 값 자체는 배열이라 평탄화 대상에서 제외됩니다. 배열 안의 {"name": "김철수"} 객체까지 파고들어 users.0.name처럼 인덱스를 붙여 펼쳐주지 않고, users 키 아래 배열이 원본 그대로 통째로 남습니다.
| 값의 형태 | 평탄화 시 처리 |
|---|---|
순수 객체 {} | 재귀적으로 들어가 하위 키를 상위키+구분자+하위키로 합침 |
배열 [] (내부에 객체가 있어도) | 재귀하지 않고 원본 배열을 그대로 값으로 유지 |
| 문자열·숫자·불린·null | 원래 키 아래 그대로 유지 |
구분자 선택이 결과를 바꾸는 경우
다음은 구분자입니다. 구분자는 Flatten에서 키를 합칠 때 쓴 문자를, Unflatten에서 다시 쪼갤 때도 똑같이 사용합니다. 원래 데이터의 키 자체에 그 구분자 문자가 이미 들어있었다면, Unflatten이 그 키를 의도한 것보다 더 잘게 쪼개버립니다.
예를 들어 {"상품가격.원": 15000}처럼 키 이름 자체에 점이 들어있는 평탄 데이터가 있다고 하겠습니다. 이걸 점(.) 구분자로 구조화하면 상품가격과 원이라는 두 조각으로 나뉘어, {"상품가격": {"원": 15000}}이라는 원래 의도에 없던 중첩 객체가 만들어집니다.
버전 번호(1.2.3)나 파일 확장자, 도메인 이름처럼 점이 포함된 키를 다룰 때 흔히 겪는 경우입니다. 이럴 때는 원본 키에 나오지 않는 문자, 예컨대 밑줄(_)이나 슬래시(/)를 구분자로 고르면 이 문제를 피할 수 있습니다.
정리
- 평탄화는 순수 객체만 재귀적으로 펼치고, "상위키+구분자+하위키" 형태의 새 키를 만듭니다.
- 배열은 객체가 아니므로 평탄화되지 않고, 내부에 객체가 들어있어도 원본 그대로 값으로 남습니다.
- 구조화는 각 키를 구분자로 쪼개 순서대로 중첩 객체를 다시 만드는 반대 과정입니다.
- 구분자는 원래 키에 없는 문자로 골라야 Unflatten 시 의도치 않은 추가 분리를 피할 수 있습니다.
- 형식이 잘못된 텍스트는 JSON.parse 단계에서 걸러져 변환 대신 오류로 표시됩니다.
입력한 JSON은 서버로 전송되지 않고 브라우저 안에서만 평탄화·구조화 변환됩니다.
자주 묻는 질문
배열 안의 객체도 평탄화되나요?
아닙니다. 값이 배열이면 그 자체가 객체가 아니라고 판정되어 재귀 대상에서 제외됩니다. 배열 안에 {"name": "김철수"}처럼 객체가 들어있어도 users.0.name처럼 인덱스가 붙어 펼쳐지지 않고, 배열이 원본 그대로 값으로 유지됩니다.
구분자는 어떤 걸 골라야 하나요?
점(.), 슬래시(/), 밑줄(_) 중에서 고를 수 있고 기본값은 점입니다. 원본 키 이름에 이미 그 문자가 들어있다면 Unflatten 시 의도치 않게 더 쪼개질 수 있으므로, 키에 나오지 않는 문자를 고르는 편이 안전합니다.
값이 null이면 어떻게 처리되나요?
null은 순수 객체로 판정되지 않으므로 재귀 대상이 아니라 원래 키 아래 그대로 유지됩니다. 하위 키로 쪼개지지 않습니다.
잘못된 JSON을 넣으면 어떻게 되나요?
JSON.parse가 실패하는 형식(따옴표 누락, 콤마 오류 등)이면 변환이 실행되지 않고 빨간색 오류 메시지가 표시되며 출력창은 비워집니다. 원본 텍스트가 유효한 JSON인지 먼저 확인해야 합니다.
