XMLの属性と子要素、JSON変換

AnsiblePlaybookを書いていて、XMLの設定ファイルを引数に応じて修正するタスクの必要性に遭遇した。
YAMLやJSONをXMLに、もしくはその逆に変換するライブラリはいくつか見かけるが
XMLの属性と子要素について、JSONやYAMLだとどういう扱いにするのがいいか、
そもそもXMLで何は属性で何は子要素なのか、知らなかったので調べたことをメモしておく。

データか、種別か

ここのページが参考になった。
https://www.w3schools.com/xml/xml_dtd_el_vs_attr.asp
XMLとして明確なルールがあるわけではなく、つまり全て属性で表現することも、全て子要素として表現することもどちらも違反ではない。
ただ、あるデータを表現する際に

  • そのデータの属性というか、オプショナルな情報なら属性に
  • そのデータを構成する、というか、なくてはならない必須の情報なら子要素に

という方針で設計するのがよさそう。
(うまく日本語で表せないが、文字通りAttributeなのか、SubElementなのか、だった)

Ansibleから離れるが、例えば、3DCGにおける頂点をXMLで表すとしたら

  • 頂点なので、座標情報は必須のデータ → 子要素に
  • 普通の頂点か、色も持つ頂点か、法線ももつ頂点か → 属性に
  • 色を持つ頂点なら、RGBAは必須のデータ → 子要素に
  • 法線を持つ頂点なら、法線ベクトルは必須のデータ → 子要素に

という感じだろうか。

<vertices>
  <vertex>
    <x>0.0</x>
    <y>1.0</y>
    <z>0.0</z>
  </vertex>
  <vertex type="color">
    <x>0.0</x>
    <y>0.0</y>
    <z>1.0</z>
    <r>255</r>
    <g>255</g>
    <b>0</g>
    <a>255</a>
  </vertex>
  <vertex type="normal color">
    <x>1.0</x>
    <y>0.0</y>
    <z>0.0</z>
    <r>0</r>
    <g>255</g>
    <b>255</b>
    <a>255</a>
    <nx>1.0</nx>
    <ny>0.0</ny>
    <nz>0.0</nz>
  </vertex>
</vertices>

オブジェクト指向言語で言えば、プロパティは子要素でクラス(継承関係)は属性、みたいな感じ?

XMLに変換するデータをJSONやYAMLで表現するには

JSONやYAMLにはAttributeという概念がなく、基本的にすべてKey:Valueのペアで保存するしかない。
一番愚直で間違いのない表記はAttributesとChildrenのプロパティを設け、そこに適宜書く事だろうか。

vertices:
  - vertex:
      attributes: {}
      children:
        x: 0.0
        y: 1.0
        z: 0.0
  - vertex:
      attributes:
        type: "color"
      children:
        x: 0.0
        y: 0.0
        z: 1.0
        r: 255
        g: 255
        b: 0
        a: 255
  - vertex:
      attributes:
        type: "color normal"
      children:
        x: 1.0
        y: 0.0
        z: 0.0
        r: 0
        g: 255
        b: 255
        a: 255
        nx: 1.0
        ny: 0.0
        nz: 0.0

attributesとchildrenという2つの予約語が新たに発生してしまうことと、
そのままXMLに変換したら本来追加されてほしくないattributesとchildrenの要素が入ってしまうのが問題。

すべて平たく書くのが、流儀に倣う方式なのだろうか。

vertices:
  - vertex:
      x: 0.0
      y: 1.0
      z: 0.0
  - vertex:
      type: "color"
      x: 0.0
      y: 0.0
      z: 1.0
      r: 255
      g: 255
      b: 0
      a: 255
  - vertex:
      type: "color normal"
      x: 1.0
      y: 0.0
      z: 0.0
      r: 0
      g: 255
      b: 255
      a: 255
      nx: 1.0
      ny: 0.0
      nz: 0.0

ただ結局、データが完全に再現できない以上変換後のデータを使うときには
設計者側で意図する通りのデータを拾ってやる処理の必要がある。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です