XML / JSON 変換

XML から JSON へ、JSON から XML へ。属性は @、テキストは #text、配列は文書全体で判断し、整形式でない XML は行と桁を示します。

インデント
入力
出力

ここに結果が表示されます

このツールの役割

XML は、たいてい誰も選んだわけではないシステムからやって来ます。SOAP のレスポンス、RSS フィード、設定ファイル、JSON より古い何かからのエクスポートといったものです。それを使わなければならないコードが求めるのは JSON です。逆の場合も同じくらいよくあり、XML しか受け付けないシステムに向かう JSON のペイロードがそれです。このページはブラウザ内で両方向に変換し、どちらの方向も一つの決まった規則で読むので、二つの方向はすべてのキーの意味について一致します。

このページが違うのは、JSON の形を、いま読んでいる要素からではなく文書全体から決め、そのことをページが伝える点です。その決定によって、ある要素が単独なら持っていたはずの形と違う形になる箇所ではどこでも、出力の下の知らせがパスと、決定が最初に適用された行と列を示します。コメントや混在内容の順序のように JSON に置き場所のないものも、消えてしまう代わりに同じように知らされ、逆方向では、XML があなたの JSON に強いる書き換えの一つひとつが、それが起きた場所で示されます。

規則: 属性には @、テキストには #text

規則は一つだけで、どの設定もそれを変えません。属性は、@ の後に属性の名前を続けて綴ったキーになり、要素をほかの何かと分け合わなければならないテキストは #text というキーの下に入ります。XML の名前は @ でも # でも始められないので、この書き方をしたキーが子要素と取り違えられることはなく、だからこそ同じ JSON を推測なしに XML へ読み戻せます。小さなカタログに当てはめると、次のとおりです。

  • ルート要素は最上位のただ一つのキーです。ルート要素が catalog の文書は、"catalog" というキーを一つだけ持つオブジェクトになります。
  • テキストしか持たない要素は、そのテキストそのものです。<title>Midnight Rain</title> は "title": "Midnight Rain" になります。
  • 属性は子要素と並ぶキーです。<book id="bk101"> ではその本に "@id": "bk101" が付き、子要素はそれぞれ、最初に現れた順にキーとして後に続きます。
  • 属性とテキストを持つ要素は、テキストを #text の下に置きます。<price currency="USD">44.95</price> は "price": {"@currency": "USD", "#text": 44.95} になります。
  • 一つの親の下で繰り返される要素は配列になります。author 要素が二度現れる本は "author": ["Gambardella, Matthew", "Knorr, Stefan"] を持ちます。
  • 名前はプレフィックスも含めて書かれたとおりに保たれます。<dc:title> は "dc:title" というキーになり、名前空間の宣言は "@xmlns:dc" のような属性のキーになり、名前空間 URI への解決は何も行われません。

エンティティと文字参照はデコードされるので、&amp; は & として、&#233; は é として届き、CDATA セクションはただのテキストです。要素のあいだに単独で置かれた空白は書式として取り除かれ、それ以外のテキストはどれも丸ごと残り、前後を削られることもありません。それでも、規格に準拠したどの XML パーサーも行う二つの正規化が先に来ます。テキストに打ち込まれた復帰は改行として届き、属性値に打ち込まれたタブや改行は空白として届きます。文書がそのどちらかを残すには、文字参照を使います。

なぜ文書全体が形を決めるのか

要素を一つずつ決めていく変換ツールは、最初の本の著者を二人いるので配列として書き、二冊目の著者を一人なので文字列として書きます。属性を持つ要素は、あるレコードではオブジェクト、次のレコードでは単なるテキストになります。最初のレコードに合わせて書いたコードは二つ目で壊れ、形が変わりうることを途中で告げるものは何もありませんでした。

そこで形はパスごとに決めます。パスとは、ルートからある要素までの要素名を /catalog/book/author のように書いたもので、位置は含まないため、どの本のどの著者も一つのパスの上に並びます。パス上の要素は、すべて一度に考え合わされます。

  • 配列。どれか一つの親の下でその要素が繰り返されていれば、パス上の要素はすべて、単独のものも含めて配列として書き出されます。
  • オブジェクト。パス上のどれか一つの要素が属性か子要素を持っていれば、そのパス上の要素はすべて、テキストしか持たないものも含めてオブジェクトとして書き出され、テキストは #text の下に置かれます。
  • 値。パスが数値として読まれるのは、その上のすべての値が変換できる場合だけで、真偽値として読まれるのは、すべての値が true か false の場合だけです。規則は、下の数値と真偽値の節で説明します。
  • 空の要素。空の要素はこれらの決定に加わらず、そのパスで決まった種類になります。

結果が、要素が単独なら持っていたはずの形と違う箇所ではどこでも、ページはパスごとに一度そう伝え、それによって変わった最初の要素の行と列を示します。ある本には著者が何人もいて、別の本には一人しかいないカタログでは、その一人の著者もやはり配列になります。ある価格は currency 属性を持ち、別の価格は持たない場合、属性のないほうの価格もやはりオブジェクトになり、テキストは #text の下に入ります。どちらも知らされるので、それを読むコードを驚かせることはありません。

レコードが一つだけのサンプルと、「常に配列」の欄

形は、それを決める元になった文書以上に良くはなりません。本が一冊だけのカタログを貼り付けると、その本はオブジェクトに、ただ一人の著者は文字列に、価格は数値になりますが、同じカタログでも二冊目の本が隣にあれば、本は配列になります。貼り付けたものの中でどこでも一度しか現れないパスは単一の値のままで、値がたまたますべて変換できるパスは、ゼロで始まる郵便番号を含む文書が届くまで数値のままです。サンプルがどれだけ代表的かで、JSON がどれだけ頼れるかがちょうど決まるので、できるときはいつもレコードを二つ以上貼り付けてください。

配列については、サンプルに頼らない手当てがあります。文書に何が現れても配列でなければならない要素名またはパスを、カンマか空白で区切って「常に配列」に入力すると、指定が一致するパスはどれも、一度しか現れない場所も含めて、どこでも配列として書き出されます。

  • item のような名前だけの指定は、item という名前の要素で終わるすべてのパスに、それがどこにあっても一致します。
  • /rss/channel/item のようなパスはそのパスだけに一致します。書き方は出力の下に並ぶパスと同じなので、そこからコピーできます。
  • 一致は厳密です。大文字と小文字は区別され、プレフィックスは名前の一部なので、Item はどの item にも一致せず、link はどの atom:link にも一致しません。
  • この欄が配列にしたパスは、ほかの決定と同じく一つずつ知らされます。名前でもパスでもない指定や、文書のどの要素にも一致しなかった指定は欄の下に並べられ、当てはまる指定はそのまま効き続けます。

この欄は「XML から JSON」の方向に属します。方向を切り替えて戻しても入力した内容は残りますが、ページのほかの設定と同じく、訪問をまたいで保持されることはありません。値にはこうした欄がありません。サンプルに何が入っていてもテキストのままでなければならないパスのためにあるのが、「数値と真偽値を変換」をオフにすることで、その代わりにほかの値もすべてテキストになります。

数値と真偽値、そして 02134 がテキストのままである理由

XML ではすべてがテキストで、数値に見えるテキストを JSON の数値に変えるのは、たいてい望むことです。けれどもそれは、郵便番号 02134 が 2134 になり、長い注文番号が末尾の桁を失う道でもあります。ここでの規則はこのサイトの CSV 変換ツールが使うものと同じで、特別な場合の一覧を必要としません。テキストが数値になるのは、その数値を書き戻したときにテキストを正確に綴る場合だけです。42 はそうなるので変換されます。02134 はそうならず、1.50、+5、1e5、倍精度ではすべての桁を保てないほど長い整数も同じです。真偽値は小文字の true と false ちょうどだけです。

このページが加えるのは、その規則をパス全体に一度に当てはめることです。パスが数値として読まれるのはその上のすべての値が変換できる場合だけ、真偽値として読まれるのはすべての値が真偽値である場合だけです。桁を失う値が一つでもあったり、一つのパスに数値と真偽値が両方あったりすれば、そこにある値はすべてテキストのまま残ります。パス上の属性名は、一つずつ別々に決まります。値の一部は変換できたのにテキストのまま残されたパスは、パスを示して知らされ、属性の場合は /catalog/book/@id のように、パスは属性で終わります。

「数値と真偽値を変換」はページを開いた時点でオンになっていて、CSV のページで対応するスイッチがオンになっているのと同じです。オフにすると、すべての値がテキストとして書き出されます。名前空間の宣言の値は、オンでもオフでも数値として読まれることはありません。Namespaces in XML の規格が、その値を名前空間名、つまりテキストとして定めているからです。

空の要素と、文書が自ら示す null

  • 空の要素は、そのパスで決まった種類になります。テキストのパスでは空文字列です。数値や真偽値のパスでは null で、ページはそのことを知らせます。単独なら、その要素は空のテキストになっていたからです。
  • 空とは何もないことです。<zip> </zip> は空白を持っており、空白はテキストです。
  • すべての要素が空のパスはテキストなので、どの要素も空文字列になります。そこには数値として読めるものが何もなく、null にすれば、文書が一度も与えていない情報になってしまいます。
  • オブジェクトとして書き出されるパスでは、パス上のほかの要素がテキストを持っていれば、空の要素にも #text が付き、同じ規則で空か null になります。<price currency="USD">5</price> と並ぶ <price/> は {"#text": null} になります。src 属性だけを持つ画像の要素のように、パス上のどの要素もテキストを持たない場合は、どれにも #text は付きません。

文書は null を自分で示すこともできます。xsi:nil="true" の印が付き、そのプレフィックスが XML Schema instance 名前空間に結び付けられている要素は、「数値と真偽値を変換」がどう設定されていても、どのパスでも null です。その印は、データではなく null だと文書が述べる手段なので、その属性も、ほかに何も結び付けない名前空間の宣言も、JSON には現れません。その名前空間に結び付けられたプレフィックスならどれでもよく、i:nil="1" も同じことを述べます。xsi:nil="false" は普通のデータで、nil の印が付いていてもなお内容を持つ要素はそのまま残されます。null として読むと、その内容を何も言わずに捨てることになるからです。

JSON に置き場所のないものは、失われずに知らされる

XML 文書が持つものの一部には、JSON に置き場所がありません。意味を持つものは、黙って捨てられるのではなく、出力の下で知らされます。

  • 混在内容の順序。<p>Hello <b>world</b>, again</p> では、テキストは #text の下に "Hello , again" としてまとめられ、b 要素は "b" の下に入ります。文字も要素もすべて残りますが、並んでいた順序は残りません。名前が入れ替わりながら並ぶ子要素も、同じように順序を失います。これはその内容を持つ要素のパスごとに一度だけ、順序が本当に失われた場合にだけ知らされるので、<p><b>Note:</b> the rest</p> では何も出ません。キーの順序がそれを保つからです。
  • コメントと処理命令。これらは省かれ、種類ごとに一つの知らせが、いくつあったかと、最初のものがどこにあるかを伝えます。
  • DOCTYPE。これも省かれ、その知らせは DTD を適用していないことを伝えます。このツールは DTD を読まないので、DTD が属性に宣言する既定値は JSON にありません。
  • 先頭の XML 宣言。これは知らせなしに省かれます。データが何であるかではなく、テキストがどうエンコードされているかを述べるものだからです。

JSON を XML に戻す: 最も近い XML と、一つずつ示される書き換え

方向を切り替えると、同じ規則が逆向きに働きます。@ のキーは属性に、#text はその要素のテキストに、配列は項目ごとに一つの要素に、それ以外のキーは子要素になり、子要素はキーが並ぶ順に置かれます。null は xsi:nil="true" の印が付いた空の要素として書き出され、XML Schema instance 名前空間は、null を書き出すときにだけ、ルート要素で一度だけ宣言されます。そのため JSON に戻すと、空文字列ではなく再び null になります。解析できない JSON と、変換するには入れ子が深すぎる JSON を除けば、拒否されるものは何もありません。あなたの JSON が、XML ではそのまま運べない形をしている箇所では、最も近い整形式の XML が書き出され、その書き換えが出力の下で、このサイトの JSONPath テスターに貼り付けられる JSONPath とともに示されます。

  • ルート要素がちょうど一つではないもの、つまり最上位にキーが複数あるもの、一つもないもの、最上位の配列、あるいは単独の値は、<root> の中に書き出されます。
  • XML の名前ではないキーは、隣にあるほかのキーが使っていない最も近い名前で書き出されます。first name は first_name に、1st は _1st になります。
  • どのキーも名前を与えていない配列の項目は、別の配列の中にあっても最上位にあっても、<item> 要素として書き出されます。
  • オブジェクトや配列を持つ @ のキーや #text は、子要素として書き出されます。属性にもテキストにも、それを入れることはできないからです。
  • null を持つ @ のキーは省かれ、子要素と並んで null を持つ #text も省かれます。XML が null と言えるのは、要素全体についてだけだからです。
  • XML 1.0 が参照としてさえ含められない文字は置き換えられ、ページはその場所を伝えます。

エスケープは整形式の XML を書くことの一部であって、選べるものではありません。< と & は常にエスケープされます。属性値の中では二重引用符もエスケープされます。値はその二つに挟まれて書かれるからです。そこにあるタブ、改行、復帰は文字参照として書き出されます。そうしなければ、パーサーがそれを空白に変えてしまうからです。テキストの中では、復帰は参照として書き出されます。そうしなければ、パーサーがそれを改行に変えてしまうからで、]]> がそのまま書き出されることもありません。こうして値は、書いたとおりの値として読み戻せます。

戻すと何になるかを、変換する前に伝える

整形式であっても、書き出す元になった JSON とは違うものとして読み戻される XML があります。そこでページは、書き出したばかりの XML を逆方向と同じ規則で読み、答えが違う箇所を伝えます。項目が一つの配列は、同じ要素が文書のどこか別の場所で一つの親の下に繰り返されていない限り、そのただ一つの項目として読み戻されます。空の配列は要素を書き出さず、空の #text はテキストを書き出さないので、どちらも何もないものとして読み戻されます。属性にも子要素にも書き出されるものを何も持たないオブジェクトは単純な値として読み戻され、別の場所にある同じ要素のために、あなたの JSON になかった配列やオブジェクトを文書が決めることになる箇所も、やはり伝えられます。どの場合も、あなたの JSON にあるとおりに書き出され、知らされます。

「入力として使う」は出力を入力欄に移して方向を切り替えるので、何が戻ってくるか、そしてそれが何を知らせるかを、ワンクリックで見られます。何も知らされない箇所では、XML が保たないものを除いて、戻ってくるのはあなたの JSON です。XML のテキストは、値が数値だったのか、真偽値だったのか、文字列だったのかを記録しません。「数値と真偽値を変換」がオンなら、数値を正確に綴る文字列はその数値として戻ることがあり、オフならすべての値がテキストとして戻ります。そして属性や、空か null の #text は、隣り合うキーのあいだで違う位置に戻ることがあります。XML はその位置を保たないからです。

XML の側から一周するときの約束は、意図して少なくしてあります。貼り付けたテキストは戻ってきません。宣言、書式、コメントなど、行きの変換で知らされたものはすべてなくなります。変わらないのは、ページが書き出す XML です。それを同じ設定で JSON に変換してまた戻すと、同じ XML が戻ってきます。

XML や JSON が読めないとき

XML パーサーが読めない文書は、何が問題かを述べる一文とともに拒否され、示せる位置がある場合は行と列も添えられます。閉じられていない要素、引用符で囲まれていない属性値、参照を始めていない & には、それぞれ専用の一文があります。まだ開いている要素と対応しない閉じタグはそのことを伝え、続けてその要素に必要な閉じタグを示すので、開いたままの要素の名前が分かります。解析できない JSON も同じように拒否され、測れる場合は、パーサーが止まった行と列が示されます。

位置を示す一文の下には、問題の文字に印を付けたあなた自身の行が表示されます。これがいちばん役立つのは、文書全体が 1 行になっている圧縮された XML や JSON です。長い行は印の周りの部分まで短くされ、切った場所には省略記号が付きます。テキストの終わり、タブ、バイト順マークのように何も描かれない問題の文字には、目に見える代わりの記号の上に印が付きます。列は JavaScript が文字列を数えるのと同じく UTF-16 コード単位で数えるので、印より前に絵文字やまれな漢字があると、列は 1 ではなく 2 進みます。

サイトが許すより深く入れ子になった文書も、どちらの方向でも拒否され、その一文が上限を示します。

よくある質問

一つだけの要素が配列として書き出されるのはなぜですか?
同じパス上の要素が文書のどこか別の場所で一つの親の下に繰り返されていて、パスは文書全体に対して一度だけ決まるからです。その結果、値を配列として読むコードは、要素が一つだけのレコードも含めて、どのレコードでも動きます。ページはパスを示し、これによって変わった最初の要素の行と列を添えます。サンプルに一つしかない場所で配列にしたいときは、その要素を「常に配列」に指定してください。
私の JSON で数値が引用符に囲まれているのはなぜですか?
同じパス上のどれかの値が、数値としては生き残れないからです。先頭のゼロ、小数点の後の末尾のゼロ、プラス記号、指数のいずれかのため、あるいはそのパスに数値と真偽値が両方あるためです。そうしたパスはどこでもテキストになり、ページはそのパスを示します。値がすべて、数値を書き戻したときの書き方、つまり 02134 ではなく 2134 のように書かれていれば、そのパスの値は変換されます。
コメント、処理命令、DOCTYPE はどうなりますか?
JSON からは省かれ、種類ごとに、いくつあったかと、最初のものがどこにあるかが知らされます。DOCTYPE の知らせは DTD を適用していないことも伝えます。そのため、DTD が宣言する属性の既定値はありません。
私の XML を DTD や XSD と照らし合わせて確かめますか?
いいえ。整形式の XML を読み、文書を読めなかった箇所を伝えますが、DTD や XSD に対する検証はせず、DTD が宣言するものを何も適用しません。だから DOCTYPE は、黙って無視されるのではなく、適用していないことが知らされるのです。
null は XML でどう書かれ、戻ってきますか?
xsi:nil="true" の印が付いた空の要素として書かれ、XML Schema instance 名前空間はルート要素で一度だけ宣言されます。その XML を JSON に戻すと再び null になります。ただの空の要素なら、テキストとして読まれるパスではどこでも空文字列として戻ったはずです。あなたの JSON がすでに自分の名前に xsi というプレフィックスを使っているなら、ページは代わりに空いているプレフィックスを宣言します。
空白を含むキーはどうなりますか?
XML が認める最も近い名前で書き出されるので、first name は first_name になり、ページはそのキーを JSONPath で示し、なった名前を添えます。その JSONPath をこのサイトの JSONPath テスターに貼り付ければ、その書き換えが適用されたすべての値を選択できます。
戻しても元の XML にならないのはなぜですか?
XML ファイルが持つものの一部 — 宣言、要素間の書式、コメント、処理命令、DOCTYPE、混在内容の順序 — には、JSON に置き場所がないからです。意味を持つものは、行きの変換で知らされています。変わらないのは、ページが書き出す XML です。それを同じ設定で JSON にしてまた戻せば、同じ XML が戻ってきます。
私が貼り付けたものはサーバーに送られますか?
いいえ。どちらの方向も完全にブラウザ内で動くので、貼り付けた文書が、API のレスポンスでも、フィードでも、認証情報を含む設定ファイルでも、端末の外に出ることはありません。

関連するツール