views:

120

answers:

1

I'm passing a dynamic zip file location to a def from a database. I want to unzip the file to a temp location, extract the xml report file inside, apply an xslt stylesheet, copy it as an rhtml to a view directory for rendering, and delete the temp extracted xml file. The functionality is working fine (the rhtml file is overwritten each time and renders) except it is extracting from the same parent zip for each execution and the extracted xml can not be deleted which leads me to believe that the first execution is not closing the parent zip (releasing its handle). Therefore, subsequent executions are extracting the xml from the first zip executed. I've tried "Zip::ZipFile.close", "zipFile = Zip::ZipFile.open(fileLocation); zipFile.close","File.close(fileLocation)", and other permutations. Any help would be appreciated.

A: 

Can you pass a block to Zip::ZipFile.open? This will close it when the block exits:

Zip::ZipFile.open(file_name) do |zip_file|
  zip_file.extract('report.xml', '/tmp')
end

# zip file is closed at this point
# apply_xslt
# copy rhtml to app/views/...
# etc

== EDIT ==

Based on your comments, here's a working example:

require 'rubygems'
require 'zip/zip'
require 'fileutils'

zip_file_name = 'test.zip'
out_dir = 'tmp_for_zip'
FileUtils.mkdir_p out_dir

Zip::ZipFile.open(zip_file_name) do |zip_file|
  report_name = File.basename(zip_file.name).gsub('zip', 'xml')
  out = File.join(out_dir, report_name)
  zip_file.extract(report_name, out) unless File.exists?(out)
  puts "extracted #{report_name} to #{out}"
end

Also, I don't know if you are running a unix, but you can use lsof (list open files) to find out if the file is actually open:

lsof | grep your_file_name
hgimenez
I don't know the name of the 'report.xml'. I've been doing it dynamically with a loop:Zip::ZipFile.open(file.to_s) { |zip_file| zip_file.each { |f| @base = File.basename(f.name) @f_path = File.join(tempDir,@base) FileUtils.mkdir_p(File.dirname(@f_path)) zip_file.extract(f, @f_path) unless File.exist?(@f_path) zip_file.close } }The name of the 'report.xml' has the same root name as the zip ("blah_report.xml" is in "blah_report.zip") so I guess I could parse it but that seems like a pain (and not too effecient - or elegant)
Alan Scott
Is there a way to do "zip_file.extract(first,'/tmp')"? There will only be 1 report per zip.
Alan Scott
Unfortunately your code yields the same result as my original. I still have 2 problems. Once the xml is extracted I use it to create an XML Document object, apply an XSLT stylesheet, and copy the result to "views/.../sampleReport.rhtml" to render. The original xml can not be deleted (thru code or by hand) until the server is shut down to release the file. (Is it possible that the Doc object is still holding on to it, not the zip parent). Also, rendering a new rhtml always shows the result of the first execution even though I verified that the rhtml has changed. Could this be a caching problem?
Alan Scott
# This is the code that follows the previous extraction block. stylesheet_doc = XML::Document.file('C:/Ruby/dashboard/public/xslt/sampling.xslt')stylesheet = LibXSLT::XSLT::Stylesheet.new(stylesheet_doc) xml_doc = XML::Document.file(@out) # @out is the extracted xmlresult = stylesheet.apply(xml_doc)resultFile = File.new("app/views/lotdetail/sampleReport.rhtml",'w')resultFile.puts resultresultFile.closeif File.exists?(File.dirname(@out)) File.delete(@out) #this failsendredirect_to :action => 'sampleReport'
Alan Scott