share facebook facebook twitter menu hatena pocket slack

2018.10.22 MON

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

甲斐 甲

WRITTEN BY 甲斐 甲

概要

勘違いから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翻訳)

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

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

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

making YAML 1.2 a superset of JSON.

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

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

類似の規格として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

元記事はこちら

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

甲斐 甲

甲斐 甲

2018/7にJOIN。 最近の好みはサーバレスです。なんでもとりあえず試します。

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。