繁体   English   中英

Ruby:如何在 XML 上映射模型

[英]Ruby: How to map a model on XML

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

每个服务都有一个 ID、一个名称、一个类型和一个图像索引

但我想要 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 元素的子元素?

我应该至少创建两个其他资源:一个request和一个choice (以及更多,基于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>

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

这个答案真的只是给猪化妆。 因为制作您自己的基于 XML 的对象持久性根本没有任何好处(没有人这样做是有原因的),并且您本可以更好地使用它只是需要时间。 如果数据不符合严格的模式,只需使用 Mongoid 或其他一些 NoSQL 数据库。

第一步是将导入移动到模型中并使其减少:

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 中的关联一样。 但为什么?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM