Elixir から XML コンバーター
Elixir の struct やマップを貼り付けると、きれいな XML が返ります。
このツールについて
Elixir アプリを古い SOAP エンドポイントに接続したり、XML-RPC 連携テスト用のフィクスチャを用意したりするとき、struct はあるけどエンベロープがない、という場面があります。フィールドごとに XmlBuilder.element/3 を手書きするのはすぐに飽きます。ここに Elixir を貼り付けてください — %Order{} リテラル 1 つでも、defstruct 入りの defmodule でも、モジュールをいくつか含むファイル丸ごとでも構いません — 整形された XML が一発で返ってきます。XmlBuilder が組み立てるのと同じ形で、儀式抜きで。
このコンバーターは Elixir のセマンティクスを理解しています。アトムは先頭のコロンが消え — マップキーの :is_paid は要素名 is_paid になり、true / false はテキストとして残ります。Decimal.new("249.99") はラッパーが取れて 249.99 になります。DateTime、NaiveDateTime、Date は ISO-8601 文字列として出ます。ネストした struct(shipping_address: %Address{} フィールドを持つ %Order{} など)はその場で展開され、nil の値は捨てられずに空要素になります。[sku: "SKU-101", qty: 2] のようなキーワードリストは同等のマップと同じ扱いです。
リストはコンテナ要素になり、各アイテムが struct 型の名前を持つ子要素として並びます。items: [%OrderItem{}, %OrderItem{}] フィールドは <items><OrderItem/><OrderItem/></items> になります。これは SweetXml が XML を Elixir に読み戻す方法や、裏で使われている xmerl ライブラリが期待する形と一致します。タプルには <tuple> ラッパーと位置付きの子要素が付きます。defmodule ブロックを複数貼り付ければ、どの defstruct も出力に入ります。.ex や .exs ファイルに書かれている通りに貼り付けて大丈夫です — 整形不要です。
使い方
3 ステップ。struct を 1 つ貼っても、Phoenix のコンテキストファイル丸ごと貼っても同じです。
Elixir を貼り付け(またはサンプルを試す)
Elixir を左のエディタにそのまま貼り付けてください。defstruct、%Struct{} リテラル、素の map、キーワードリスト、ネストした struct — すべて OK。サンプルを読み込む をクリックすれば、現実的な Order / OrderItem / Address の例が入ります。
@moduledoc を外したり、@derive 注釈を消したり、パイプやコメントを整理したりする必要はありません。エディタで見ているそのままの Elixir コード を貼り付けてください。
変換をクリック
緑色の 変換 ボタンを押してください。ツールが Elixir を読み、すべてのフィールドを保持し、ネストした struct を保ち、一発で XML を組み立てます。処理中は短いローディング表示が出ます。
XML をコピー
右パネルにインデント済みで整形された XML が表示されます。SOAP リクエストボディ、XML-RPC 呼び出し、テストフィクスチャ、連携スイートのシードファイルにそのまま貼り付けてください。
実際に役立つ場面
SOAP サービスと話す Phoenix アプリ
Phoenix コンテキストから渡ってくるのはきれいな <code>%Order{}</code>。でも接続先ベンダーは SOAP しか話さない。struct を貼り付ければ XML エンベロープのボディが出るので、リクエストに入れるだけ — <code>XmlBuilder</code> ツリーを手作業で組む必要はありません。
XML-RPC 連携
古い WordPress プラグイン、レガシーな CMS、金融フィード — 今でも XML-RPC を話します。Elixir struct を仕様通りの <code><param><value><struct></code> 形に変換して、そのまま <code>HTTPoison</code> に流せます。
レガシーな企業システム連携
銀行ファイル、EDI フィード、HL7 風のヘルスケアペイロード。パートナーが XML を譲らないなら、すでに持っている Elixir モデルを貼り付けて対応する XML テンプレートを得る方が、<code>xmerl</code> と一から格闘するより速いです。
SweetXml のラウンドトリップ用フィクスチャ
SweetXml で XML を読んで struct と比較するテストを書いていますか? struct を貼り付けて XML を取得し、フィクスチャとして保存してください。ラウンドトリップの一貫性が保てます。
よくある質問
defmodule / defstruct ブロックを複数まとめて貼り付けられますか?
はい。ファイル丸ごと貼り付けて構いません。どの defstruct もフィールドをそのまま保って出力され、ネストした struct 参照も展開されます。末尾に実値入りの %Struct{} リテラルを含めれば、その値が使われます — 含めなければ空要素を持つ形が出ます。
アトムはどう扱われますか?
マップ / struct のキーとして使われたアトムは要素名になります(先頭のコロンが外れ、:is_paid は is_paid になります)。値がブール系アトム(true、false、nil)の場合は対応するテキストになります。それ以外のアトムはコロンを外したテキストとして出ます(:pending は pending)。元のアトム構文が必要なら、パース後に String.to_atom/1 で後処理してください。
Decimal、DateTime、Date、NaiveDateTime はどうなりますか?
Decimal.new("249.99") はラッパーが外れて 249.99 になります。DateTime、NaiveDateTime、Date は ISO-8601 文字列として出ます。Time は HH:MM:SS になります。nil 値は捨てられず空要素になるので、SweetXml のラウンドトリップでも形が一貫します。
リスト、タプル、キーワードリストはどう変換されますか?
struct のリストはコンテナ要素となり、各子要素は struct 名を持ちます。items: [%OrderItem{}, ...] は <items><OrderItem/><OrderItem/></items> になります。スカラーのリストはコンテナ内で <item> 子要素になります。タプルには <tuple> ラッパーが付き、位置付き子要素 <_0/>、<_1/> が並びます。キーワードリストはマップと同じ扱いで、各キーが子要素になります。
Jason / Poison 用の @derive を使っている struct はどうなりますか?
@derive 注釈は JSON ライブラリ向けのコンパイル時ヒントなので、XML 出力には影響しません。struct のすべてのフィールドはデフォルトで出力されます。フィールドを省きたい場合は、貼り付け前に defstruct リストから外すか、値を "スキップ" として認識できる何かで包んでください。
コードは保存されますか?
コードは変換のためにバックエンドに送られますが、保持はしません — ペイロードをログには残しません。オンラインツールの常として、本当に機密性が高いコードは、貼り付ける前に目を通してください。
他にも使えそうなツール
Elixir から XML はパズルの 1 ピースにすぎません。以下のツールと相性が良いです: