Ruby:如何在XML上映射模型

问题描述 投票:-1回答:2

在Ruby-on-Rails 6.0中,我想使用模型,视图和控制器创建一个名为services的资源。

每个服务都有一个ID,一个名称,一个类型和一个ImageIndex

但是我希望模型映射到XML(请参见下文)而不是ActiveRecord。我希望这些动作(索引,显示,新建,编辑和销毁)修改XML本身。

我的第一个尝试是将代码添加到控制器中以解析XML,如下所示:

  def index
    @services = []

    f = File.open("xml/eidos/LeftTree/Services.xml")
    doc = Nokogiri::XML(f)
    f.close
    root = doc.root
    tags = root.xpath("Tag")

    tags.each do |tag|
      @service = Service.new
      @service.node_name = tag.xpath("NodeName").text
      @service.text = tag.xpath("Text").text
      @service.image_index = tag.xpath("ImageIndex").text
      @services << @service
    end

    @services 
  end

此操作成功,并向我返回了完整的实例列表。我对def Show做相同的操作(请注意,我不需要编辑或删除XML)

现在的中间问题是:

我如何管理主要Tag元素的子代?

我应该创建至少两个其他资源:requestchoice(还有更多,基于type元素的内容,而我的方法看起来并不干净。

最后一个问题是:

这就是为什么我想找到/构建一种类似于ActiveRecord的方法,在其中可以列出资源的属性和关系的原因。

朝这个方向有什么建议吗?

示例XML如下所示:

<Services>
  <Tag>
    <ID>X401ED7DA027C</ID>
    <Name>Accertamento Ici Con Adesione</Name>
    <Type>Service</Type>
    <ImageIndex>0</ImageIndex>
  </Tag>
  <Tag>
    <ID>X3F9BEB550223</ID>
    <Name>Cambio di abitazione</Name>
    <Type>Service</Type>
    <ImageIndex>0</ImageIndex>
    <Tag>
      <ID>X3F9BEB550223/X400E4CBA032E</ID>
      <Name>Richiesta Di Cambio Di Abitazione</Name>
      <Type>Request</Type>
      <ImageIndex>1</ImageIndex>
      <Tag>
        <ID>X3F9BEB550223/X400E4CBA032E/X40091B660349_X3FFF3E980118</ID>
        <Name>Allegato</Name>
        <Type>Choice</Type>
        <Multiplicity>
          <MinOccurrence>0</MinOccurrence>
          <MaxOccurrence>*</MaxOccurrence>
        </Multiplicity>
        <Required>False</Required>
        <ImageIndex>5</ImageIndex>
        <IDRole>X40091B660349</IDRole>
        <NameSpace>OggettiCondivisi</NameSpace>
      </Tag>
    </Tag>
  </Tag>
</Services>
ruby-on-rails ruby xml nokogiri ruby-on-rails-6
2个回答
0
投票

ActiveRecord没有对平面文件数据库的内置支持。如果要使用ActiveRecord,建议您使用一种受支持的数据库,并从XML导入/导出。


0
投票

这个答案实际上只是在给猪上妆。因为建立自己的基于XML的对象持久性根本没有任何好处(这是没有人这样做的原因),您将需要花费一些时间来更好地利用它。如果数据不遵循严格的架构,则只需使用Mongoid或其他NoSQL db。

第一步是将输入移动到模型中,并减少它的吸引力:

class Service
  include ActiveModel::Model
  include ActiveModel::Attributes
  attribute :node_name, String
  attribute :text, String
  attribute :image_index, String

  def self.import(fn = "xml/eidos/LeftTree/Services.xml")
    doc = Nokogiri::XML(File.read(fn))
    tags = doc.root.xpath("Tag")
    tags.map do |tag|
      Service.new(
        node_name: tag.xpath("NodeName").text,
        text: tag.xpath("Text").text,
        image_index: tag.xpath("ImageIndex").text
      )
    end
  end
end

这将使您将控制器的动作细化为:

def index
  @services = Service.import
end

#each仅在仅关心循环的副作用而不是返回值的情况下才应使用。例如:

@users.each do |u|
  u.send_welcome_email!
end

对于其他,请使用#map或可枚举的其他方法,例如#collect#reject ...

您还将为循环的每次迭代重新分配实例变量@service。了解实例变量和局部变量之间的区别。而且要分配的局部变量的数量要少一些。您不需要将所有内容都分配给变量-特别是如果您只使用过一次则不需要。

您想要在模型(甚至是单独的服务对象)中进行导入的原因是,控制器很难测试。它们具有大量的依赖关系,真正测试它们的唯一好方法是通过HTTP请求间接进行。控制器是在Rails中将所有内容捆绑在一起的粘合代码-请勿肿它们。

另一方面,模型很容易测试,因为您只需调用Service.import并编写关于结果的断言。

而且我希望操作(索引,显示,新建,编辑和销毁)修改> XML本身。

玩得开心。您将需要使用Nokogiri来加载和修改文档树。在[[n小时后,您将建立一些基本上可以完成数据库功能的事情,但是由于它根本无法扩展,因此在所有方面都变得更糟。

这就是为什么我想找到/建立像ActiveRecord替换,我可以在其中列出属性和我的资源之间的关系。

再次-浪费时间。您可以只使用ActiveModel::Model创建某些东西,就像在ActiveRecord中进行关联一样。但是为什么呢?

© www.soinside.com 2019 - 2024. All rights reserved.