2008-09-17 9 views
7

XSDを持たず、オブジェクトモデルを作成したいという適度に複雑なXML構造(数十の要素、何百もの属性)がある場合、定型文from_xml()とto_xml()メソッドを書くことを避けるエレガントな方法は何ですか?例えば素早く汚れたXMLシリアル化のためのRubyコード?

、与えられた:

<Foo bar="1"><Bat baz="blah"/></Foo> 

私は無限のシーケンスの書き込みを回避するにはどうすればよい:

class Foo 
    attr_reader :bar, :bat 

    def from_xml(el) 
    @bar = el.attributes['bar'] 
    @bat = Bat.new() 
    @bat.from_xml(XPath.first(el, "./bat") 
    end 
etc... 

を私は明示的にオブジェクト構造を作成する気にしません。それは私がちょうど確信している直列化は


私はラインやクラスごとに2つを保存しようとしておりません(初期化子にfrom_xml行動を移動することで...いくつかのより高いレベルのプログラミングでの世話をすることができますかクラスメソッドなど)。

「すべての要素がクラス名になることはわかっています。すべてのXML属性がフィールド名になることはわかっています。代入するコードは@#{attribute_name} = el。[#{attribute_name}]だけで、サブ要素に再帰し、to_xmlを逆にします。


「ビルダー」クラスとXmlSimpleが正しいパスに見えるという提案に同意します。 XML - >ハッシュ - >? - >オブジェクトモデル(!と利益)


更新2008-09-18 AM:@Roman、@fatgeekuk、および@ScottKoonから優秀な提案はオープン、問題が壊れているように見えます。 HPricotのソースをダウンロードして問題の解決方法を確認しました。主要なメソッドは明らかにinstance_variable_setとclass_evalです。

@bar = el.bar:IRBの仕事は、今、あなたはそれはあなたがすることができます不足しているメソッドを定義することができます....実現に向けて非常に興奮し

答えて

0

を非常に励みに動いていますか?それはいくらかの定型文を取り除くだろう。コウモリは、常にそのように定義されようとしている場合は、initializeメソッドにXPathをプッシュすることができ、

class Bar 
    def initialize(el) 
    self.from_xml(XPath.first(el, "./bat")) 
    end 
end 

HpricotまたはREXMLはあまりにも役立つかもしれません。

1

to_xmlメソッドを作成する代わりにBuilderを使用し、from _xmlメソッドを使用する代わりにXMLSimpleを使用してXMLファイルをHashにプッシュすることができます。残念ながら、私はあなたが本当にこれらのテクニックの使用からそれほど多くを得るのかどうかはわかりません。

0

parsing the XML with hpricotを試してみて、普通の古いRubyオブジェクトを出力することができますか? [免責事項]私はこれを試していない。

0

私はto_xmlとfrom_xmlをビルドするためにattr_accessorをサブクラス化します。

このような何かあなたが好きそれを使用することができ

class XmlFoo 
    def self.attr_accessor attributes = {} 
    # need to add code here to maintain a list of the fields for the subclass, to be used in to_xml and from_xml 
    attributes.each do |name, value| 
     super name 
    end 
    end 

    def to_xml options={} 
    # need to use the hash of elements, and determine how to handle them by whether they are .kind_of?(XmlFoo) 
    end 

    def from_xml el 
    end 
end 

(ノートでは、これが唯一のアウトライン、完全に機能していない)....

class Second < XmlFoo 
    attr_accessor :first_attr => String, :second_attr => Float 
end 

class First < XmlFoo 
    attr_accessor :normal_attribute => String, :sub_element => Second 
end 

が、これは一般的なアイデアを与える願っています。

1

私は最初にXmlSimpleを使用することをお勧めします。入力ファイルでXmlSimple#xml_inを実行すると、ハッシュが取得されます。次に、あなたがそれ(obj.instance_variables)に再帰し、例えば、同じ名前のオブジェクトにすべての内部ハッシュ変えることができます(element.is_a(ハッシュ)?を):

obj.instance_variables.find {|v| obj.send(v.gsub(/^@/,'').to_sym).is_a?(Hash)}.each do |h| 
    klass= eval(h.sub(/^@(.)/) { $1.upcase }) 

おそらくきれいな方法を見つけることができますこれをする。 その後、この新しいオブジェクトからxmlを作成する場合は、XmlSimple#xml_outを変更して別のオプションを受け入れる必要があります。これは、引数として受け取る通常のハッシュとオブジェクトを区別し、あなたのバージョンのXmlSimple#value_to_xmlメソッドを書かなければならないので、ハッシュ構造にアクセスしようとするのではなくアクセッサメソッドを呼び出すでしょう。別のオプションは、必要なインスタンス変数を返すことによって、すべてのクラスが[]演算子をサポートするようにすることです。

関連する問題