본문으로 건너뛰기
jsonbeautifiers
한국어

YAML을 JSON으로

다중 문서 스트림을 지원하고, YAML 1.1 불리언 함정을 켜고 끌 수 있습니다.

YAML
JSON

붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기

YAML을 JSON으로 변환합니다. 다중 문서를 지원하고, 가장 큰 혼란을 일으키는 타입 규칙을 켜고 끄는 스위치도 있습니다.

일이 틀어지는 건 이 방향이고, 거의 전부가 여러분의 다른 도구들이 YAML 몇 버전을 구현했는지로 귀결됩니다.

노르웨이 문제, 직접 확인해 보기

YAML 1.1에서 따옴표 없는 no, yes, on, off, y, n은 불리언입니다. 그래서 노르웨이를 뜻하는 NO가 들어간 국가 목록은 false로 읽힙니다. YAML 1.2에서는 평범한 문자열입니다.

이게 중요한 이유는 이 분열이 생태계 전체를 관통하기 때문입니다. PyYAML, 루비의 Psych, 그리고 여러 오래된 도구가 1.1을 구현합니다. js-yaml, Go의 yaml.v3, 그리고 대부분의 현대 파서는 1.2를 구현합니다. 같은 파일이 읽는 쪽에 따라 다른 뜻이 됩니다.

여기서 타입 규칙을 바꾸면 값이 눈앞에서 달라지는 걸 볼 수 있습니다. js-yaml 5.4.1로 측정한 결과, `a: no`는 YAML 1.2에서 문자열 "no", YAML 1.1에서 불리언 false가 됩니다. 1.2 모드에서도 따옴표 없는 no나 yes를 보면 이 도구는 경고합니다. 파이프라인의 다음 도구가 같은 해석을 하리라는 보장이 없기 때문입니다.

YAML에는 있고 JSON에는 없는 나머지 것들

주석
영구히 사라집니다. JSON에는 주석 문법이 없습니다. YAML을 손으로 관리한다면 이건 일방통행 변환입니다.
앵커와 별칭
자리에서 펼쳐집니다. 앵커를 다섯 번 쓰는 문서는 JSON에서 사본 다섯 개가 되고, 크기가 상당히 커질 수 있습니다.
타임스탬프
YAML은 날짜처럼 생긴 스칼라를 진짜 날짜로 해석합니다. JSON에는 날짜 타입이 없어서 ISO 8601 문자열로 씁니다. 처음부터 평범한 문자열로 두고 싶다면 JSON 타입 규칙을 고르세요.
문자열이 아닌 키
YAML은 숫자나 심지어 시퀀스도 매핑 키로 허용합니다. JSON은 안 되므로 문자열로 변환합니다.
.inf와 .nan
JSON에 대응물이 없어서 null이 됩니다.
여러 문서
---로 구분된 스트림에는 문서가 여러 개 들어 있습니다. 기본적으로 첫 번째만 변환하고 더 있었다고 알려 줍니다. "모든 문서"를 켜면 배열로 받습니다.

탭 문자

YAML은 들여쓰기에 탭을 쓰는 것을 예외 없이 완전히 금지합니다. 가장 흔한 YAML 오류이고, 편집기가 탭을 넣도록 설정되어 있어서 생깁니다. 이 도구는 파싱을 시도하기도 전에 탭에 대해 경고합니다. 그 경우 어떤 파서가 내놓는 메시지든 도움이 안 되기 때문입니다.

How to do this in code

코드에서의 변환, 그리고 함께 따라오는 보안 이야기.

py Python

PyYAML은 YAML 1.1을 구현하므로, "no"가 False가 되는 지점이 바로 여기입니다.

import yaml, json

# safe_load, never load. yaml.load can construct arbitrary Python
# objects and has been a real remote-code-execution vector.
data = yaml.safe_load(text)
print(json.dumps(data, indent=2, default=str))

# default=str handles the datetime objects PyYAML produces for
# date-shaped scalars, which json.dumps otherwise refuses.
sh Shell
yq -o=json eval . input.yaml > output.json

# Every document of a multi-document stream
yq -o=json eval-all '[.]' input.yaml
js JavaScript

js-yaml은 YAML 1.2를 구현하므로 여기서는 "no"가 문자열로 남습니다.

import { load, loadAll } from 'js-yaml';

const data = load(text);              // YAML 1.2 core schema
const docs = loadAll(text);           // multi-document stream
go Go
import "gopkg.in/yaml.v3"

var v any
if err := yaml.Unmarshal(data, &v); err != nil { return err }
out, _ := json.MarshalIndent(v, "", "  ")

자주 묻는 질문

제 값이 왜 true나 false가 되었나요?
YAML 1.1 파서로 읽고 있기 때문입니다. 거기서는 no, yes, on, off, y, n이 불리언입니다. 값에 따옴표를 붙이거나 YAML 1.2 파서를 쓰세요. 위의 타입 규칙을 바꿔 보면 여러분 문서에서 차이를 직접 볼 수 있습니다.
제 주석은 어디로 갔나요?
JSON에는 주석이 없어서 버려집니다. 우회할 방법이 없습니다. YAML이 여러분이 관리하는 파일이라면 그쪽을 원본으로 두고 JSON은 생성물로 다루세요.
파이썬에서 yaml.load가 왜 위험한가요?
문서 안의 태그로부터 임의의 파이썬 객체를 만들어 낼 수 있어서, 신뢰할 수 없는 YAML을 파싱하는 것이 곧 실행하는 것과 같아지기 때문입니다. 항상 safe_load를 쓰세요.