JSON から YAML への変換

JSON を YAML に変換し、追加した引用符ごとに理由を説明 — 引用符がなければ静かに真偽値や数値や日付になる文字列を示します。

入力
YAML
name: deploy
country: 'NO'
startsAt: '12:30'
mode: '0755'
version: '1.10'
released: '2024-01-30'
enabled: 'yes'
script: |-
  set -e
  npm run build
  npm test
replicas: 3
tags:
  - web
  - edge
各文字列が引用符で囲まれた理由

引用符で囲まれた値: 6 個。 YAML 1.1 でのみ必要なもの: 4 個。上のスキーマを切り替えると違いが分かります。

  • country1.1 のみ

    「NO」は真偽値の false として読まれてしまいます。

  • startsAt1.1 のみ

    「12:30」は 60 進数として 750 と読まれてしまいます。

  • mode

    「0755」は先頭が 0 のため、数値の 493 として読まれてしまいます。

  • version

    「1.10」は数値の 1.1 として読まれてしまいます。

  • released1.1 のみ

    「2024-01-30」はテキストではなく日付として読まれてしまいます。

  • enabled1.1 のみ

    「yes」は真偽値の true として読まれてしまいます。

このツールの役割

JSON 文書を YAML に変換し、それから各文字列がなぜ引用符に収まったかを教えます。その二つ目の部分がツールの存在理由です: ほかのすべての変換器は出力を返し、あなたの値の一つがもう文字列でないことを後で見つけさせます。

変換は一方向に動きます。YAML を読むことはそれを書くよりずっと大きな問題で、部分的に正しい YAML パーサーはまったくないより悪いです — ファイルを受け付け、文句を言わずに誤ったデータを返します。出力は境界があるので、それがここで覆われる方向です。

なぜ変換器に見解が要るのか

JSON はすべてが何の型かを言います。文字列は引用符を持ち、数値は持たず、三つ目の可能性はありません。YAML は代わりに、引用符のない値の型をその形を見て決めます: 真偽値のパターンに合えば真偽値、数値に合えば数値、何にも合わなければ初めてテキストとして残ります。

それが YAML を手で書いて心地よくするものであり、それへの変換を判断の要ることにするものです。入力のすべての文字列が、YAML が解決するすべてのパターンに対して確認され、合えば引用符が付けられねばなりません。安全な方向で誤ると出力がうるさくなり、もう一方の方向で誤ると値が黙って型を変えます。

ノルウェー問題と、その親戚

最もよく知られた場合は国コードの一覧です。ノルウェーは NO で、YAML 1.1 では引用符のないトークン NO は真偽値の false です。国を列挙する設定ファイルがノルウェーを失い false を得て、どこでも何もエラーを報告しません。

それは一つの奇妙な規則ではなくその一族です。YAML 1.1 は y・Y・yes・no・on・off のすべてを、あらゆる大文字化で真偽値として読み、化学記号・スイッチの位置・問いへの答えを捕らえます。そして数値の解決器はさらに奇妙です:

  • 12:30 は 750 です。YAML 1.1 はコロン区切りの数字を 60 進数として読むので、時刻や時間の長さが整数になります。
  • 0755 は 493 です。先頭のゼロは YAML 1.1 で 8 進数を意味し — YAML 1.2 では同じテキストが 10 進数の 755 なので、二つの版はどちらの数かで食い違い、どちらであるかではありません。
  • 1.10 は 1.1 です。二部構成のバージョン番号は浮動小数点で、末尾のゼロが消えます。1.10 に固定された依存関係が今や 1.1 を指します。
  • 2024-01-30 は文字列ではなく日付オブジェクトです。YAML 1.1 がタイムスタンプ型を持つからです。
  • 空の文字列は null で、素の語 null・Null・NULL とチルダも同じです。

これらのどれも YAML のバグではありません。解決器が、たまたま合うテキストに対して、約束どおりのことをしているのです。唯一の防御は合うものを何でも引用符で囲むことで、それがこのツールがすることであり、findings パネルが一行ずつ説明することです。

二つの版と、なぜ古いほうが既定なのか

YAML 1.2 は 2009 年に到着し、驚きの解決器のほとんどを取り除きました。そのコアスキーマは true と false だけを真偽値として保ち、60 進数をまるごと落とし、タイムスタンプ型を持ちません。1.2 では NO も 12:30 も 2024-01-30 もすべてただの文字列です。

落とし穴は、実際にあなたのファイルを読むものです。PyYAML は YAML 1.1 を実装し、PyYAML は膨大な量のツール — Ansible、古い Kubernetes クライアント、無数のスクリプト — の背後のパーサーです。Go の yaml.v3 と現行の js-yaml は 1.2 に従います。だから同じ文書が、誰が開くかによって二つの異なるふうに読まれえて、どこでも安全な唯一の出力は 1.1 向けに引用符を付けたものです。

それがここの既定です。設定を 1.2 に切り替えても何も隠しません — 新しい解決器で再出力し、findings パネルが縮むので、どの引用符が古いスキーマのためにあったかを正確に見られます。残るものが、すべてのパーサーが必要とするものです。

型ではなく構文を壊す文字列

二つ目の文字列の集まりが別の理由で引用符を要します: YAML がそれらを別の型として読むからではなく、そもそもテキストとして解析されないからです。

  • 空白が続くコロンはキーを終わらせます。「note: time: now」は、値がキー「time」であるキー「note」として読まれるでしょう。
  • ハッシュが続く空白はコメントを始めるので、その後のすべてが消えます。
  • 先頭の -・?・:・[・]・{・}・#・&・*・!・|・>・%・@ やバッククォートは指示文字で、構造的な何かを意味します。
  • 先頭や末尾の空白は引用符のない値に保たれないので、" x " は "x" として返ってきます。
  • 値のどこかのタブはただちに拒否されます — PyYAML は誤読するのではなく文書全体を拒むので、これは大声で失敗します。

単一引用符は足りるところではどこでも使われます。ちょうど一つのエスケープ規則 — アポストロフィは二度書く — を持ち、二重引用符が持ち込むバックスラッシュのエスケープより読みやすいからです。二重引用符は、本当にエスケープが要る場合のために取ってあります: 制御文字、タブ、そしてブロックを使えない複数行の文字列です。

複数行の文字列とチョンピング指示子

改行を含む文字列 — スクリプト、証明書、散文の塊 — が、そもそも誰かが YAML を欲しがる理由であることが多いです。JSON はそれを、とても長い一行にバックスラッシュ n のエスケープでしか書けません。YAML はリテラルのブロックスカラーを持ち、パイプで導入され、そこではテキストが下にインデントされて読める形で現れます。

微妙なのは末尾の改行に何が起きるかで、それはチョンピング指示子で制御されます:

  • 素のパイプはクリップします: ブロックが末尾の改行をいくつ持っても、値はちょうど一つを得ます。
  • マイナスが続くパイプはストリップします: 値は一つも得ません。
  • プラスが続くパイプはキープします: 値はそのすべてを得ます。

このツールは与えられた文字列から指示子を選ぶので、値は往復を正確に生き延びます。知っておく価値があるのは、既定 — 素のパイプ — が人が手で書くもので、二つの改行やゼロの改行で終わった文字列を黙って正規化するからです。

ブロックスカラーはすべてを運べず、運べないところでは出力が二重引用符に退き、findings パネルがなぜかを言います。復帰は生き残りません。ブロックスカラーが改行を正規化するからです。空白で始まる最初の行は余分なインデントとして読まれ剥がされるでしょう。そして空白で終わる行は仕様では保たれますが画面では見えず、ほとんどのエディターが保存時に取り除くので、それを引用符で囲むのがより安全な選択です — それは限界ではなく決定で、そう報告されます。

複数の文書

YAML は JSON が持たないものを持ちます: ファイルが三つのダッシュで分けられた文書の流れを保持できます。それが Kubernetes マニフェストの形式で、JSON 配列がしばしば YAML シーケンス以外の何かになる必要がある理由です。

ここのスイッチはトップレベル配列の各要素を独自の文書として出力します。そして入力がまったく単一の JSON 値ではなく、すべての行がそれぞれ解析されるとき、それは NDJSON — ログや API エクスポートが届く行区切りの形式 — として読まれ、各行が文書になります。その読みは推測なので、黙ってではなく出力の上に報告されます。

その退避は、入力全体が解析に失敗し、すべての行が成功するときにだけ当てはまり、単に不正なだけの文書はそうしません。構文エラーは今も構文エラーとして、それが起きた行と列とともに現れます。

変換が保てないもの

二つのものが、このツールがあなたのデータを見る前に、両方とも JSON の解析そのもので失われ、どちらかを知る価値があります。

重複するキー。JSON はオブジェクトが同じキーを二度並べるのを許し、ほとんどのパーサーは黙って最後を保ちます。YAML は重複をまったく禁じるので、出力は有効ですが、より早い値は既に消えています — そして変換器は決して受け取らなかったものを報告できません。

整数の精度。約 9000 兆より大きな JSON 数値は倍精度に解析されるのを生き残らないので、12345678901234567890 のような ID は丸められて返ってきます。これは YAML の問題ではなく、このツールが持ち込む問題でもありません。この言語のすべての JSON パーサーで起きます。大きな識別子が重要なら、両側で文字列に属します。

出力についての注記

インデントは常にスペースです。YAML がインデントのタブをまったく禁じるからで — それは形式が厳格である数少ないことの一つです。スペース 2 個が慣習で、4 個は一部のハウススタイルが欲しがるので提供されます。

シーケンスはそのキーの下にインデントされます。それもインデントのない形も合法な YAML で同じことを意味します。インデントされたほうが、ほとんどの人が書き、ほとんどのエディターが正しく畳むものです。

空の配列やオブジェクトは、括弧か波括弧の対としてフロースタイルで書かれます。ブロックスタイルには空を表す術がないからで — 続く行に書くものが何もありません。

出力は改行で終わり、それは几帳面さではなく荷重を担います。ブロックスカラーのチョンピングはそれに続く改行に対して測られるので、最後の改行のないファイルのまさに末尾のクリップされたブロックは、保つはずだった改行を失います。

Kubernetes マニフェストと、文字列のままでなければならない欄

Kubernetes はマニフェストをどちらの形式でも読みます。その公式の文書は YAML を慣例と呼び、JSON を代わりに使えるものとして挙げていて、kubectl はマニフェストを、要求を行うときに JSON か、API が支える別の直列化形式へ変換します。つまり変換はクラスターが受け取れるかどうかの話ではありません。手元に残るファイルの話です: レビュアーが読むのは YAML で、プルリクエストの差分が読めるのも YAML で、コメントを運べるのは二つのうちこちらだけです。JSON はふつう kubectl get -o json から、テンプレートから、あるいはオブジェクトを返す API から届きます。

  • 一つのファイル、複数のオブジェクト。マニフェストは三つのダッシュで区切って一つのファイルにまとめられ、文書はそれらが現れた順に作られると明言しています — だから Service はそれを満たす Deployment より上に書くのがふつうです。トップレベル配列の各要素を独自の文書として出力するスイッチが、JSON のオブジェクト一覧をそういうファイルに変えます。
  • コンテナーの環境の項目は二つの文字列の欄です。API の文書は name も value も文字列と定義しているので、"true" という JSON の値は引用符を付けたまま出なければなりません: 引用符がなければそれは真偽値で、真偽値はその欄が保つと定義された型ではありません。
  • コンテナーのポートは整数と定義されていて、その文字列たちから数行のところに座っています。二つには逆の扱いが要り、JSON はすでにその区別を運んでいます — 数は素の数になり、文字列は YAML がそれを文字列として読まなくなる場所でだけ引用符を付けられます。
  • ラベルと注釈は文字列から文字列への写像です。マニフェストの中でノルウェー問題が着地するのはそこです: 値が NO・on・off のラベルは YAML 1.1 のパーサーには真偽値で、値 1.10 は末尾のゼロを失う浮動小数点です。

三つの環境の項目を、すべての値が文字列の JSON として与えると、こう変換されます:

env:
  - name: DEBUG
    value: 'true'
  - name: REPLICAS
    value: '3'
  - name: COUNTRY
    value: 'NO'

三つとも引用符が付き、findings パネルは三つとも、それぞれがなっていた値とともに名付けます: ‏true は真偽値、3 は数、NO は真偽値の false です。版に依るのは最後の一つだけで — スキーマを 1.2 に切り替えるとその引用符は外れます。1.2 は NO をテキスト以外の何とも読まないからです。ほかの二つは両方の版で引用符を保ちます。

Docker Compose — 形式自身の文書が YAML について警告する場所

Compose ファイルは YAML で、Docker のその文書は YAML の解析について二つの警告を載せています。製品自身の文書が自分の直列化形式を危険として名指すのは珍しく、二つの警告はどちらもこのツールが存在する理由そのものについてです: テキストであるはずの値を、パーサーが別のものとして読むこと。

  • ポート。文書は HOST:CONTAINER の対応づけを常に引用符付きの文字列として書くべきだと言います。YAML の 60 進の浮動小数点との衝突を避けるためです。引用符がなければ 22:22 は整数の 1342 です。
  • 環境の値。文書は true・false・yes・no を引用符で囲み、パーサーがそれらを変換しないようにと求めます。四つのうち二つは YAML の両方の版で真偽値、二つ — yes と no — は 1.1 だけで真偽値なので、findings パネルはそれらを違うふうに印します。
  • 60 進の規則が届くのは、コロンの後の数が六十より小さい対応づけだけです。それが 60 進の一桁が覆う範囲だからです。だから 22:22 はここで引用符が付き 8080:80 は素のまま残り、その違いはどのポートが大事かという判断ではなく規則です。

ポートと環境の値が JSON ではすべて文字列であるサービスは、こう変換されます:

services:
  proxy:
    image: nginx
    ports:
      - '22:22'
      - 8080:80
    environment:
      TLS_ENABLED: 'no'
      DEBUG: 'true'

それが文書の求める出力で、既定のスキーマがそれを作ります。それはスキーマに触れない最も明快な理由でもあります: 1.2 に切り替えるとポートの対応づけと no は引用符を失い、true は自分の引用符を保ちます。1.2 は 60 進を捨て、真偽値として true と false だけを残したからです。1.2 を実装したパーサーなら結果を正しく読みます — けれども Docker の助言はそんな条件を一つも付けずに書かれていて、それに従う代価は引用符二組です。

よくある質問

JSON は既に有効な YAML ですか?
YAML 1.2 では、はい: 仕様がそう明言し、1.2 パーサーは JSON ファイルを直接読みます。実務ではあまり役立ちません。変換する理由は読みやすさ — コメント、ブロックスカラー、波括弧なし — で、JSON を YAML ファイルに貼り付けてもそのどれも得られないからです。YAML 1.1 ではまったく真ではなく、それが二つの版を見分ける価値のあるもう一つの理由です。
私の文字列が、要らなそうな引用符を得たのはなぜですか?
ほぼ確実に要ります。YAML は引用符のない値をパターンの照合で型付けするので、NO・yes・off・12:30・0755・1.10・2024-01-30 と空の文字列がすべて文字列でなくなります。findings パネルはそれぞれを名付け、それがなっていた値を示すので、信じるのではなく主張を確認できます。YAML 1.2 パーサーを狙うなら、スキーマを切り替えると 1.1 だけが要るものが取り除かれます。
ここでの YAML 1.1 と 1.2 の違いは何ですか?
1.2 は驚きのほとんどを引き起こす解決器を落としました: yes/no/on/off はもう真偽値でなく、60 進数はなくなり、タイムスタンプ型はありません。PyYAML は 1.1 を実装し今もいたるところにあるので、保守的な出力が既定です。1.2 の設定は、何がファイルを読むか分かっているときのためにあります。
YAML を JSON に戻せますか?
いいえ、意図的に。YAML の読み手はアンカー・エイリアス・タグ・マージキー・五つのスカラースタイル・二つのスキーマ版を要し、そのどれかを微妙に誤ると、ファイルを受け付けて含まれていたのと違うデータを返すことになります。その失敗は静かで、それが機能を提供しないより悪くします。
Kubernetes 形式の複数文書ファイルをどう得ますか?
トップレベル配列の各要素を独自の文書として出力するスイッチをオンにすると、配列が三つのダッシュで分けられた文書になります。入力が代わりに NDJSON — ログや API エクスポートがしばしばそうであるように、一行に一つの JSON オブジェクト — なら、それは自動的に検出され出力の上に報告されます。
出力にコメントがないのはなぜですか?
入力になかったからです。コメントは YAML が持ち JSON が欠く主なもので、変換器はそれをでっち上げられません。これはもう一方の向きでも覚えておく価値があります: YAML ファイルを JSON で往復させると、その中のすべてのコメントが消えます。
私が貼り付けたものはサーバーに送られますか?
いいえ。解析と変換はすべてブラウザ内で動きます。何もアップロードも記録もされず、ネットワーク接続なしで動きます。
kubectl の JSON 出力を YAML マニフェストにどう変換しますか?
貼り付けて YAML を読んでください。Kubernetes は両方の形式を受け取ります — その文書は YAML を慣例、JSON を代わりのものと呼びます — なので変換する理由は、クラスターが受け取るかどうかではなく手元に残るファイルです。確かめるべきは引用符です: マニフェストは API が文字列と定義する欄で満ちていて、環境の値やラベルと注釈の値もその中にあり、それらこそ YAML が型を変えてしまうものです。JSON が複数のオブジェクトの一覧なら、複数文書のスイッチがそれを一つのファイルにします。
なぜ Docker Compose はポートを引用符で囲ませたいのですか?
YAML 1.1 のパーサーにとって 22:22 は数の対ではなく、60 進の一つの数 — 1342 だからです。Docker の Compose の文書はまさにその理由で HOST:CONTAINER の対応づけを常に引用符付きの文字列にすべきだと言い、同じページは環境のブロックの true・false・yes・no も引用符で囲むよう求めます。どちらもこのツールが既定のスキーマで行うことで、findings パネルはどの引用符がどの規則から来たかを言います。コロンの後の数が六十以上の対応づけ、たとえば 8080:80 は 60 進の規則の外なので素のまま残ります。
Kubernetes や Docker Compose にはどの YAML の版を選ぶべきですか?
既定の 1.1 です。それが付ける引用符はどれも 1.2 のパーサーも受け取るので、保守的な出力はどちらにしても安全で、Compose の文書の二つの警告はどちらも 1.1 の規則についてです — 60 進のポートの対応づけと、真偽値としての yes と no。1.2 の設定は、古いスキーマのためだけにある引用符がどれかを見せるためにあります。出力はそれを失い、それはあの警告が求めることの逆です。

関連するツール