QA@IT
«回答へ戻る

回答を投稿

用途次第だと思いますが、私はRubyのクラスにマッピングする方が良いと思います。

これがベストかどうかは分かりませんが、Railsのコンポーネントの一部であるactivemodelを利用するのはどうでしょうか?
XMLとRubyオブジェクトを相互変換する機能があり、単体のライブラリとして利用する事ができます。

サンプルで書くとこんな感じでしょうか。

require 'active_model'

class Entry
  include ActiveModel::Model
  include ActiveModel::Serializers::Xml

  attr_accessor :title, :body, :foo

  def attributes=(hash)
    hash.each do |key, value|
      instance_variable_set("@#{key}", value) # インスタンス変数を動的に定義する
    end
  end

  def attributes
    {"title" => nil, "body" => nil, "foo" => nil}
  end
end

entry = Entry.new("title" => "EntryTitle", "body" => "EntryBody")
puts entry.to_xml
# <?xml version="1.0" encoding="UTF-8"?>
# <entry>
#   <title>EntryTitle</title>
#   <body>EntryBody</body>
#   <foo nil="true"/>
# </entry>


xml = <<XML
<?xml version="1.0" encoding="UTF-8"?>
<entry>
  <title>Title</title>
  <body>Body</body>
</entry>
XML

new_entry = Entry.new
p new_entry.from_xml(xml)
# => #<Entry:0x007ff8f3848a98 @title="Title", @body="Body">

attributesattributes=はこのライブラリが要求している規約です。それぞれfrom_xmlメソッドとto_xmlメソッドの内部で利用されます。
詳しくはリファレンスに説明があります。

上記の例ではアクセサメソッドは普通に定義していますが、method_missingdefine_methodを組み合わせる事でもっと動的に属性値を定義する事は可能です

ただ、あるRailsが想定している形に縛られてしまうので、上手く噛み合わない場合は無理に使わない方が良いでしょう。

自分でパーサを準備する場合も、このサンプルの様な形で動的にインスタンス変数を定義したりmethod_missingdefine_methodを使えば、ある程度冗長な記述を削減する事ができると思います。

もしXMLをパースする場合はNokogiriというライブラリを利用する事が多いですね。

用途次第だと思いますが、私はRubyのクラスにマッピングする方が良いと思います。

これがベストかどうかは分かりませんが、Railsのコンポーネントの一部であるactivemodelを利用するのはどうでしょうか?
XMLとRubyオブジェクトを相互変換する機能があり、単体のライブラリとして利用する事ができます。

サンプルで書くとこんな感じでしょうか。

```ruby
require 'active_model'

class Entry
  include ActiveModel::Model
  include ActiveModel::Serializers::Xml

  attr_accessor :title, :body, :foo

  def attributes=(hash)
    hash.each do |key, value|
      instance_variable_set("@#{key}", value) # インスタンス変数を動的に定義する
    end
  end

  def attributes
    {"title" => nil, "body" => nil, "foo" => nil}
  end
end

entry = Entry.new("title" => "EntryTitle", "body" => "EntryBody")
puts entry.to_xml
# <?xml version="1.0" encoding="UTF-8"?>
# <entry>
#   <title>EntryTitle</title>
#   <body>EntryBody</body>
#   <foo nil="true"/>
# </entry>


xml = <<XML
<?xml version="1.0" encoding="UTF-8"?>
<entry>
  <title>Title</title>
  <body>Body</body>
</entry>
XML

new_entry = Entry.new
p new_entry.from_xml(xml)
# => #<Entry:0x007ff8f3848a98 @title="Title", @body="Body">

```

`attributes`と`attributes=`はこのライブラリが要求している規約です。それぞれ`from_xml`メソッドと`to_xml`メソッドの内部で利用されます。
詳しくはリファレンスに説明があります。

- http://api.rubyonrails.org/classes/ActiveModel/Serialization.html
- http://api.rubyonrails.org/classes/ActiveModel/Serializers/Xml.html

上記の例ではアクセサメソッドは普通に定義していますが、`method_missing`と`define_method`を組み合わせる事でもっと動的に属性値を定義する事は可能です

ただ、あるRailsが想定している形に縛られてしまうので、上手く噛み合わない場合は無理に使わない方が良いでしょう。
。
自分でパーサを準備する場合も、このサンプルの様な形で動的にインスタンス変数を定義したり`method_missing`と`define_method`を使えば、ある程度冗長な記述を削減する事ができると思います。

もしXMLをパースする場合は[Nokogiri](http://nokogiri.org/ "Nokogiri")というライブラリを利用する事が多いですね。