2

我想使用Builder来构建一组基于 ActiveRecord 模型表的 XML 文件。我有将近一百万行,所以我需要使用它find_each(batch_size: 5000)来迭代记录并为每批记录编写一个 XML 文件,直到记录用尽。类似于以下内容:

filecount = 1
count = 0
xml = ""
Person.find_each(batch_size: 5000) do |person|
  xml += person.to_xml  # pretend .to_xml() exists 
  count += 1       

  if count == MAX_PER_FILE
    File.open("#{filecount}.xml", 'w') {|f| f.write(xml) }
    xml = ""
    filecount += 1
    count = 0
  end
end

这不适用于 Builder 的界面,因为它希望在块中工作,如下所示:

xml = builder.person { |p| p.name("Jim") }

块结束后,Builder 关闭其当前节;您不能保留对 p 的引用并在块之外使用它(我尝试过)。基本上,Builder 想要“拥有”迭代。

因此,要使这项工作与 builder 一起工作,我必须执行以下操作:

  filecount = 0
  offset = 0
  while offset < Person.count do
    count = 0
    builder = Builder::XmlMarkup.new(indent: 5)
    xml = builder.people do |people|
      Person.limit(MAX_PER_FILE).offset(offset).each do |person|
        people.person { |p| p.name(person.name) }
        count += 1
      end
    end

    File.open("#output@file_count.xml", 'w') {|f| f.write(xml) }
    filecount += 1
    offset += count
  end

有没有办法在没有块语法的情况下使用 Builder?有没有办法以编程方式告诉它“关闭当前节”而不是依赖一个块?

4

2 回答 2

1

根据 Larry K 的建议,我最终手动生成了 XML。Ruby 的内置 XML 编码使这变得轻而易举。我不确定为什么这个功能没有得到更广泛的宣传......to_xs在偶然发现内置的"foo".encode(xml: :text).

我的代码现在看起来像:

  def run
    count = 0
    Person.find_each(batch_size: 5000) do |person|
      open_new_file if @current_file.nil?

      # simplified- I actually have many more fields and elements
      #
      @current_file.puts "     <person>#{person.name.encode(xml: :text)}</person>"

      count += 1

      if count == MAX_PER_FILE
        close_current_file
        count = 0
      end
    end

    close_current_file
  end

  def open_new_file
    @file_count += 1
    @current_file = File.open("people#{@file_count}.xml", 'w')
    @current_file.puts "<?xml version='1.0' encoding='UTF-8'?>"
    @current_file.puts "     <people>"
  end

  def close_current_file
    unless @current_file.nil?
      @current_file.puts "     </people>"
      @current_file.close
      @current_file = nil
    end
  end
于 2012-06-25T21:14:32.393 回答
1

我的建议:不要使用生成器。

只要您正确转义 xml 实体,XML 就是一种简单的格式。

批处理您的数据库检索,然后将批处理作为 xml 写入文件句柄。如您的示例所示,不要通过字符串缓冲。只需写入文件句柄。让操作系统处理缓冲。文件可以是任意大小,为什么有限制?

另外,不要包括缩进空间,百万行,它们会加起来。

添加 了在编写xml文件时,我还在文件顶部包含了xml注释:

  • 生成 xml 文件的软件名称和版本
  • 写入文件的日期/时间戳
  • 其他有用的信息。例如,在这种情况下,您可以说该文件是原始数据集的批次 #x。
于 2012-06-26T02:20:03.637 回答