Как получить XML-документ из загруженного zip-файла в rails

#ruby-on-rails #ruby #xml

#ruby-на-рельсах #рубин #xml — файл #ruby-on-rails #ruby #xml

Вопрос:

Я использовал Typhoeus для потоковой передачи zip-файла в память, затем перебираю каждый файл для извлечения XML-документа. Для чтения XML-файла я использовал Nokogiri, но получаю сообщение об ошибке, Errno::ENOENT: No such file or directory @ rb_sysopen - my_xml_doc.xml .

Я просмотрел ошибку и увидел, что ruby, скорее всего, запускает скрипт не в том каталоге. Я немного запутался, нужно ли мне сначала сохранить XML-документ в памяти, прежде чем я смогу его прочитать?

Вот мой код для дальнейшего уточнения:

Контроллер

 def index
  url = "http://feed.omgili.com/5Rh5AMTrc4Pv/mainstream/posts/"
  html_response = Typhoeus.get(url)
  doc = Nokogiri::HTML(html_response.response_body)

  path_array = []
  doc.search("a").each do |value|
    path_array << value.content if value.content.include?(".zip")
  end

  path_array.each do |zip_link|
    download_file = File.open zip_link, "wb"
    request = Typhoeus::Request.new("#{url}#{zip_link}")
    binding.pry

    request.on_headers do |response|
      if response.code != 200
        raise "Request failed"
      end
    end

    request.on_body do |chunk|
      download_file.write(chunk)
    end

    request.run

    Zip::File.open(download_file) do |zipfile|
      zipfile.each do |file|
        binding.pry
        doc = Nokogiri::XML(File.read(file.name))
      end
    end
  end

end
  

файл

 => #<Zip::Entry:0x007ff88998373
@comment="",
@comment_length=0,
@compressed_size=49626,
@compression_method=8,
@crc=20393847,
@dirty=false,
@external_file_attributes=0,
@extra={},
@extra_length=0,
@filepath=nil,
@follow_symlinks=false,
@fstype=0,
@ftype=:file,
@gp_flags=2056,
@header_signature=009890,
@internal_file_attributes=0,
@last_mod_date=18769,
@last_mod_time=32626,
@local_header_offset=0,
@local_header_size=nil,
@name="my_xml_doc.xml",
@name_length=36,
@restore_ownership=false,
@restore_permissions=false,
@restore_times=true,
@size=138793,
@time=2016-10-17 15:59:36 -0400,
@unix_gid=nil,
@unix_perms=nil,
@unix_uid=nil,
@version=20,
@version_needed_to_extract=20,
@zipfile="some_zip_file.zip">
  

Комментарии:

1. Вы всегда знаете, каким будет диапазон размеров этих XML-файлов? Если нет, и если у них есть возможность быть довольно большими, вы можете сохранить их на диске, прежде чем манипулировать ими.

2. Я не всегда буду знать размер, спасибо за предложение! В конечном итоге я буду помещать XML непосредственно в список Redis. (Еще не зашел так далеко в коде).

Ответ №1:

Это решение, которое я придумал:

Драгоценные камни:

 gem 'typhoeus'
gem 'rubyzip'
gem 'redis', '~>3.2'
  

Контроллер:

 def xml_to_redis_list(url)
  html_response = Typhoeus.get(url)
  doc = Nokogiri::HTML(html_response.response_body)
  @redis = Redis.new

  path_array = []
  doc.search("a").each do |value|
    path_array << value.content if value.content.include?(".zip")
  end

  path_array.each do |zip_link|
    download_file = File.open zip_link, "wb"
    request = Typhoeus::Request.new("#{url}#{zip_link}")

    request.on_headers do |response|
      if response.code != 200
        raise "Request failed"
      end
    end

    request.on_body do |chunk|
      download_file.write(chunk)
    end

    request.run

    while download_file.size == 0
      sleep 1
    end

    zip_download = Zip::File.open(download_file.path)
    Zip::File.open("#{Rails.root}/#{zip_download.name}") do |zip_file|
      zip_file.each do |file|
        xml_string = zip_file.read(file.name)
        check_if_xml_duplicate(xml_string)
        @redis.rpush("NEWS_XML", xml_string)
      end
    end
    File.delete("#{Rails.root}/#{zip_link}")
  end

end

def check_if_xml_duplicate(xml_string)
  @redis.lrem("NEWS_XML", -1, xml_string)
end