代码之家  ›  专栏  ›  技术社区  ›  Larry OBrien

快速脏xml序列化的ruby代码?

  •  7
  • Larry OBrien  · 技术社区  · 16 年前

    假设一个中等复杂的XML结构(几十个元素,几百个属性)没有XSD,并且希望创建一个对象模型,那么避免从_XML()和_XML()方法编写样板文件的一种优雅方法是什么?

    例如,给定:

    <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...  
    

    我不介意显式地创建对象结构;这是序列化,我确信可以通过一些更高级的编程来处理……


    我不想为每个类保存一两行(通过将XML行为从初始值设定项或类方法移到初始值设定项或类方法等)。我在寻找复制我的心理过程的“元”解决方案:

    “我知道每个元素都将成为一个类名。我知道每个xml属性都将是一个字段名。我知道要分配的代码只是@{attribute{attribute}=el。[{attribute{attribute}]然后递归到子元素中。换成XML。”


    我同意“builder”类加上xmlsimple似乎是正确的选择。XML->哈希->?->对象模型(和利润!)


    2008年9月18日上午更新:来自@roman,@fatgeekuk和@scottkoon的优秀建议似乎已经打开了这个问题。我下载了hpricot源代码,看看它是如何解决这个问题的;关键方法显然是instance_variable_set和class_eval。IRB的工作非常令人鼓舞,现在正朝着实施的方向迈进…非常兴奋

    5 回复  |  直到 11 年前
        1
  •  1
  •   Dan    16 年前

    您可以使用builder而不是创建to-xml方法,也可以使用xmlsimple将XML文件拉入散列,而不是使用from-xml方法。不幸的是,我不确定你是否真的能从这些技巧中得到那么多。

        2
  •  1
  •   Roman    16 年前

    我建议首先使用xmlsimple。在输入文件上运行xmlsimple xml_-in之后,会得到一个散列。然后可以递归到它(obj.instance_变量)中,并转换所有内部哈希(element.is_a?(hash))到同名对象,例如:

    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以接受另一个选项,该选项将对象与通常用作参数接收的散列区分开来,然后必须将xmlsimple value的版本写入xml m方法,因此它将调用访问器方法,而不是尝试访问哈希结构。另一个选择是,通过返回所需的实例变量,让所有类都支持[]运算符。

        3
  •  0
  •   Jim Deville    16 年前

    是否可以定义一个缺少的方法,使您可以执行以下操作:

    @巴=埃尔巴?这样可以去掉一些样板。如果总是这样定义bat,可以将xpath推送到initialize方法中,

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

    hpricot或rexml也有帮助。

        4
  •  0
  •   ScottKoon    16 年前

    你能试试吗 parsing the XML with hpricot 然后使用输出构建一个普通的老ruby对象?[免责声明]我没试过。

        5
  •  0
  •   jh314    11 年前

    我将子类attr_accessor来为您构建to_xml和from_xml。

    类似这样的东西(注意,这不是完全的功能,只是一个大纲)

    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
    

    希望能给大家一个大概的印象。