日本語

開発者ツール · 構文コンバーター

XML から JSON へのマッピング: 属性、テキスト ノード、および 1 対多の問題

· 仕組み

XML json データ形式

1 つの XML 項目はオブジェクトにマッピングされ、繰り返し項目は配列にマッピングされます。
オリジナル ToolAcre ベクトル イラスト

XML を JSON に変える単一の正しい方法はありません。これは、XML には、JSON にはない属性、混合コンテンツ、および順序付けされた子があるためです。この投稿では、一般的なマッピング規則とそれぞれのトラップについて説明します。

1 つの <item> がオブジェクトになり、2 つが配列になった理由 — XML フィードの JSON 形状は、エントリ数に応じて変化します

`<item>one</item>` を含むフィードは `"item": "one"` を生成します。 2 番目の兄弟を追加すると、そのプロパティが `"item": ["one", "two"]` に変更されます。両方の意味が同じ XML 構文を持つため、パーサーは、1 つの項目が概念的には 1 つの項目のリストであると推論できません。したがって、最初のサンプルのみに対してビルドされたコードは、実稼働環境が 2 番目のサンプルを送信するときに失敗する可能性があります。

ToolAcre は、always-array オプションの背後にこの不安定性を隠しません。名前を 1 つの値として記録し、繰り返される兄弟を配列として記録します。この直接マッピングは検査が簡単ですが、安定したコレクション形状を必要とするコンシューマは、スキーマの知識を使用するか、変換後に結果を自分で正規化する必要があります。

XML にあって JSON にないもの — 属性、要素と混合されたテキスト、順序付けされた兄弟、名前空間、コメント、および処理命令

XML は、子要素から属性を分離し、兄弟順序を保持し、要素間のテキストを許可し、名前空間プレフィックスを保持し、コメントと処理命令を含めることができます。 JSON はオブジェクトと配列を提供しますが、これらのノード カテゴリに相当するものが組み込まれていません。したがって、XML ~ JSON の結果は選択された投影であり、普遍的な変換ではありません。

このリーダーは、宣言、コメント、および処理命令を削除します。名前空間プレフィックスは解決されずそのまま残ります。`<ns:item>` はキー `ns:item` になり、`xmlns:ns` は `@xmlns:ns` になります。混合テキストは 1 つのキーの下に結合されるため、子要素の周囲の元の位置が失われ、変換をラウンドトリップできないという警告が表示されます。

属性の規則 - @ や $ などの接頭辞、それらが存在する理由、および同じ名前を持つ属性と子要素がどのように衝突するか

属性には `@` 接頭辞が使用されます。 `<user id="7"><id>other</id></user>` は、`"7"` に等しい `@id` と、`"other"` に等しい子 `id` を持つオブジェクトになります。接頭辞は、2 つの異なる XML 構造が 1 つのオブジェクト プロパティ内で衝突するのを防ぎます。また、JSON が XML に書き戻されるときも、コンバーターのコントラクトの一部になります。

他のライブラリは、`$`、属性オブジェクト、または別の規則を使用する場合があります。 ToolAcre は、表示される `@` マッピングのみをサポートします。ライターを変更せずにアプリケーション コードでそのプレフィックスを変更すると、属性が要素に変換されるため、変換された値を中間検査フォームとして使用するときにそれを保持します。

テキスト ノードの規則 — 要素のコンテンツには #text または _、要素にテキストと子の両方がある場合に何が起こるか

テキストのみを含む要素はその文字列に折りたたまれます。属性または子も存在する場合、テキストは `#text` の下に存在します。 CDATA は `#cdata` の下に個別に保存されます。自己終了タグは空の文字列になります。これらの予約キーを使用すると、作成者は通常の子の名前と、JSON 自体が定義していないコンテンツ カテゴリを区別できます。

混合コンテンツには損失が残ります。 `<p>before<b>bold</b>after</p>` では、結合された `#text` プロパティから子に対する相対的な「前」と「後」の位置を再構築することはできません。このツールはその構造パターンを検出し、警告します。ドキュメントの順序が意味の一部である場合は、ノードを保持する XML API を使用します。

1 対多の問題 — 繰り返される要素は繰り返された場合にのみ配列になる、そしてなぜ消費者は防御的にコーディングする必要があるのか

反復された兄弟は、反復が観察された後にのみ配列になります。単一の `<book>` が 1 つのオブジェクトです。 2 冊の本はオブジェクトの配列です。これは、1 対多の問題と呼ばれることもありますが、パーサーの欠陥ではありません。ソース文書には、その出現とは無関係にリスト宣言が含まれていないだけです。

防御的なコンシューマーは、スキーマの知識を使用して既知のパスを正規化できます。つまり、配列になっていない場合は `catalogue.book` をラップします。通常のスカラーは対称性だけを目的としたリストになってはいけないため、このルールをすべてのプロパティに適用しないでください。コンバーターは、そのようなドメイン情報の作成を意図的に回避します。

作業例: 小さな RSS スタイルのドキュメント (属性、繰り返し要素、名前空間) を変換し、結果の JSON アノテーションを付けます。

`<feed xmlns:m="https://example.invalid/meta"><item id="1"><m:title>One</m:title></item><item id="2"><m:title><![CDATA[Two & More]]></m:title></item></feed>` を変換します。ルートは `feed` です。 `@xmlns:m` は名前空間宣言を保持します。 `item` は配列です。各 `@id` はテキストです。 2 番目のタイトルには `#cdata` が含まれています。

型推論はデフォルトでオフになっているため、`id="2"` であっても文字列 `"2"` のままになります。推論を有効にすると、パーサーは数値およびブール値テキストを JavaScript タイプとして読み取ることができますが、XML はその意図を宣言していませんでした。このオプションはユーザーによって制御される推測であり、文書によって提供される証拠ではありません。

これでカバーされないもの — 要素が常にリストであることを認識するスキーマ駆動型の変換には、XSD または手動マッピングが必要です

XSD がロードされておらず、スキーマ駆動型リスト情報も利用できません。コンバーターは、要素が 1 つだけ出現する場合にその要素が反復可能であることを認識したり、必要な子を検証したり、名前空間 URI をアプリケーション タイプに解決したり、型指定されたクライアントを生成したりすることができません。解析が成功すると、構成されたリーダーによって受け入れられる整形式の XML が確立されるだけです。

DOCTYPE 宣言は、無害なものも含め、解析前に拒否されます。この境界により、外部エンティティのリクエスト、ローカル ファイルの読み取り、エンティティの拡張が妨げられます。 DOCTYPE を削除すると、ドキュメントが依存していた宣言も削除される可能性があるため、データを所有し、その結果を理解している場合にのみ削除してください。

要点: XML から JSON は変換ではなくマッピングです。また、構文コンバーター パネルを使用してブラウザーでそのマッピングを検査できる方法

結果を ToolAcre の文書化されたマッピングとして扱います: 属性の場合は `@`、混合要素テキストの場合は `#text`、CDATA の場合は `#cdata`、反復された兄弟およびリテラルの名前空間プレフィックスの後の配列。これらのルールにより、XML と JSON が 1 つのデータ モデルを共有しているかのように装うことなく、出力が予測可能になります。

検査のために、この投影法は高速で読みやすいです。永続的な統合を行うには、1 つまたは複数のオカレンス、子と名前を共有する属性、空の要素、混合コンテンツ、および名前空間をテストします。要素の順序やスキーマの制約が重要な場合は、一般的な変換された形状に依存するのではなく、そのコントラクトに対して XML を解析します。

生の XML フィクスチャを正規化された期待値のそばに置いてください。このペアリングは、依存関係のアップグレードによって配列の処理、空白のトリミング、またはエンティティのデコードが変更された場合に証拠を保存します。また、レビュー担当者は、JSON ビューでは表現できない違いを確認することができます。変換されたオブジェクトだけでは、空の文字列が自己終了要素、ペアのタグ、またはソース内の別の規則からのものであるかどうかを証明することはできません。