4
1

More than 5 years have passed since last update.

PythonのPyYAMLでJSON形式の文字列が読み込めたのが不思議で調べてみた

Posted at

概要

勘違いからjson形式の文字列を、yaml.load で読み込んでしまったのですが、エラーがでず、読み込めてしまったので、不思議に思って調べてみました。

先に結論

YAML1.2からJSONを公式サブセットとする変更が入っているそうです(知らなかった

YAML Ain’t Markup Language (YAML™) Version 1.2
http://yaml.org/spec/1.2/spec.html

This document reflects the third version of YAML data serialization language.

この改訂の主な目的は、YAMLをJSONを公式サブセットとして遵守することです。(Google翻訳)

検証

以下のように、何を思ったのかJSON形式の文字列をYAMLライブラリで読み込んでしまいました。

> pip install pyyaml
test.py
import yaml
import pprint

if __name__ == '__main__':
  jsonStr = '''
{
  "hoge": {
    "list": [
      {
        "name": "hoge",
        "value": "foo"
      },
      {
        "name": "huge",
        "value": "foo!"
      }
    ]
  }
}
  '''

  pprint.pprint(yaml.load(jsonStr))
> python test.py

{'hoge': {'list': [{'name': 'hoge', 'value': 'foo'},
                   {'name': 'huge', 'value': 'foo!'}]}}

読み込めてしまったので、あれ?YAMLとJSONって互換性あったっけ?と思い、じゃあjson ライブラリでYAML形式の文字列読み込めるの?をやってみました。

test.py
import json
import pprint

if __name__ == '__main__':
  yamlStr = '''
hoge:
  list:
  - name: hoge
    value: foo
  - name: huge
    value: foo!
  '''

  pprint.pprint(json.loads(yamlStr))
> python test.py

json.loads(yamlStr)
Traceback (most recent call last):
  File "test.py", line 14, in <module>
    pprint.pprint(json.loads(yamlStr))
  File "/Users/hoge/.anyenv/envs/pyenv/versions/3.6.6/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/Users/hoge/.anyenv/envs/pyenv/versions/3.6.6/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/Users/hoge/.anyenv/envs/pyenv/versions/3.6.6/lib/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 1)

だめでした。
PyYAMLが対応しているだけかなと、他のruamel.yamlってライブラリで試してみました。

> pip install ruamel.yaml
test.py
from ruamel.yaml import YAML
import pprint

if __name__ == '__main__':
  jsonStr = '''
{
  "hoge": {
    "list": [
      {
        "name": "hoge",
        "value": "foo"
      },
      {
        "name": "huge",
        "value": "foo!"
      }
    ]
  }
}
  '''

  yaml=YAML(typ='safe')
  pprint.pprint(yaml.load(jsonStr))
> python test.py

{'hoge': {'list': [{'name': 'hoge', 'value': 'foo'},
                   {'name': 'huge', 'value': 'foo!'}]}}

こちらでも読み込めました。
じゃあ、大抵のYAMLライブラリはJSON形式を読み込める?

と思ってRubyで試してみました。

test.rb
require 'yaml'
require 'pp'

jsonStr = <<-"EOS"
{
  "hoge": {
    "list": [
      {
        "name": "hoge",
        "value": "foo"
      },
      {
        "name": "huge",
        "value": "foo!"
      }
    ]
  }
}
EOS

pp(YAML.load(jsonStr))
> ruby test.rb
{"hoge"=>
  {"list"=>
    [{"name"=>"hoge", "value"=>"foo"}, {"name"=>"huge", "value"=>"foo!"}]}}

ほう!読み込めるんですね。

YAMLライブラリでJSONは読み込める。
JSONライブラリでYAMLは読み込めない。

なにか見えてきたので、ググってみました。

json --- JSON エンコーダおよびデコーダ
https://docs.python.org/ja/3/library/json.html

注釈 JSON は YAML 1.2 のサブセットです。

YAML Ain’t Markup Language (YAML™) Version 1.2
http://yaml.org/spec/1.2/spec.html

This document reflects the third version of YAML data serialization language.

この改訂の主な目的は、YAMLをJSONを公式サブセットとして遵守することです。
(Google翻訳)

正直、知らなかったです。

ウィキペディアを見てみると英語版の方だと、記載がありました。

making YAML 1.2 a superset of JSON.

日本語版だと類似という記述だけでした。

類似の規格としてJSONがある。

教訓

普段良く使うフォーマットの仕様はしっかり把握しておきましょう。

参考

YAML Ain’t Markup Language (YAML™) Version 1.2
http://yaml.org/spec/1.2/spec.html

YAML
https://en.wikipedia.org/wiki/YAML

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1