2018年5月27日日曜日

xmlsimple で xml_out を使ってハッシュから XML を生成する場合のコツ

概要

Ruby の xmlsimple ライブラリを使ってハッシュから XML を生成してみました
基本的な使い方から使う際のポイントを紹介します

環境

  • macOS 10.13.4
  • Ruby 2.5.1p57
  • xmlsimple 1.1.5

xml_out のサンプル

とりあえずサンプルです
今回は AWS の route53 でゾーンを作成するために必要な XML CreateHostedZoneRequest を作成してみます
ハッシュを定義してそれを食わすことで XML を出力しています

require 'xmlsimple'

body = { 
  '@xmlns' => 'https://route53.amazonaws.com/doc/2013-04-01/',
  'Name' => ['content' => ''],
  'CallerReference' => ['content' => ''],
  'HostedZoneConfig' => {
    'Common' => ['content' => ''],
    'PrivateZone' => ['content' => ''],
  },
  'DelegationSetId' => ['content' => ''],
  'VPC' => {
    'VPCId' => ['content' => ''],
    'VPCRegion' => ['content' => ''],
  }
}

options = {
  'AttrPrefix' => true,
  'RootName' => 'CreateHostedZoneRequest',
  'ContentKey' => 'content'
}

puts XmlSimple.xml_out(body, options)

結果は以下のようになります
どうしてこうなるのか詳細を説明します

<CreateHostedZoneRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/">                                                  
  <Name></Name>
  <CallerReference></CallerReference>
  <HostedZoneConfig>
    <Common></Common>
    <PrivateZone></PrivateZone>
  </HostedZoneConfig>
  <DelegationSetId></DelegationSetId>
  <VPC>
    <VPCId></VPCId>
    <VPCRegion></VPCRegion>
  </VPC>
</CreateHostedZoneRequest>

説明

XML に変換する対象のハッシュ body はとりあえずおいておきます

XmlSimple では hash -> XML の変換ルールを options で定義します
今回は AttrPrefix, RootName, ContentKey の 3 つの設定をしています
他にも様々な設定ルールがあります
(サイトは CPAN のドキュメントになります)

その中でも上記 3 つのオプションはよく使うと思います
それぞれ説明すると

  • AttrPrefix・・・@ で始まるキーがあった場合はそれを XML のタグとして使用せず属性として使用する
  • RootName・・・XML のルートドキュメントの名前を指定します、これを指定しない場合は <opt> になってしまいます
  • ContentKey・・・XML の値として使用するデータを明示的に指定することができます

となります
ここで body とそれぞれのオプションの効果を見ていきます
まず冒頭の '@xmlns' => 'https://route53.amazonaws.com/doc/2013-04-01/' ですがこれは AttrPrefix の効果でタグにはなりません
ルートの位置で定義しているのでルートの属性情報として使用されます

  • <CreateHostedZoneRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/">

次にハッシュの各所に定義してある ['content' => ''] ですが、これは ContentKey が影響します
このオプションの値とハッシュ内で使われている値がどちらも content になっているのがわかると思います
つまりこの content の値で指定したデータが XML に出力されたときのタグないのデータになるわけです
ContentKey は必須ではないですが、タグに属性が入る場合はほぼ必須になると思います
またデータとなるキーがわかりやすくもなるので使うことをおすすめします

最後に RootName ですがこれは生成したい XML ルートを指定するだけです

Tips

XML declaration を定義したい

例えば <?xml version='1.0' standalone='yes'?> の情報です
XML の先頭に付与する情報になります
XmlDeclaration というオプションが使えるのでそれを使います
先頭に追加したい文字列を直接指定することで追加することができます

options = {
  'AttrPrefix' => true,
  'RootName' => 'CreateHostedZoneRequest',
  'ContentKey' => 'content',
  'XmlDeclaration' => '<?xml version=\'1.0\' standalone=\'yes\'?>'                                                                
}

xml_in は可逆ではない

例えば今回生成できた XML をそのまま xml_in メソッドに投げも同じハッシュを得ることはできません

out = XmlSimple.xml_out(body, options)
pp XmlSimple.xml_in(out)
{"xmlns"=>"https://route53.amazonaws.com/doc/2013-04-01/",
 "Name"=>[{}],
 "CallerReference"=>[{}],
 "HostedZoneConfig"=>[{"Common"=>[{}], "PrivateZone"=>[{}]}],
 "DelegationSetId"=>[{}],
 "VPC"=>[{"VPCId"=>[{}], "VPCRegion"=>[{}]}]}

当然と言えば当然ですが上記のようになります
ハッシュからデータを取得するときに気をつけるのはデータの部分が必ず配列に格納されている点ですデータが 1 つしかなくても配列に入ります

最後に

Ruby の xmlsimple を使ってハッシュから XML を生成してみました
結構クセのある使い方をするのとドキュメントが少ないのが辛い点です

ハッシュから XML に変換するのであればこの方法でも良いですが単純に XML を欲しいだけであれば nokogiri や rexml でも生成できます
もしくは erb を使って XML をテンプレート化すればそこからでも XML 情報を生成することができます

今回紹介した方法も XML を生成する手段の一つにしかすぎませんので各自の環境にあった最適な方法を選択するようにしてください

0 件のコメント:

コメントを投稿