Skip to content

Instantly share code, notes, and snippets.

@iwadon
Created September 11, 2009 14:43
Show Gist options
  • Save iwadon/185322 to your computer and use it in GitHub Desktop.
Save iwadon/185322 to your computer and use it in GitHub Desktop.
# Based on: http://www.simplegimmick.com/2007/06/read-ods-like-csv/
require 'rubygems'
require 'nokogiri'
require 'zip/zipfilesystem'
class ODS
Error = Class.new(StandardError)
def self.open(filename)
ods = new
ods.parse_file(filename)
yield ods
end
def parse_file(filename)
docbytes = nil
Zip::ZipFile.open(filename) do |zipfile|
docbytes = zipfile.file.read('content.xml')
end
@doc = Nokogiri(docbytes)
self
end
def sheet(name)
element = @doc.search("//table:table[@table:name='#{name}']")[0]
raise Error, "sheet `#{name}' not found" if element.nil?
Sheet.new(element)
end
class Element
def initialize(element)
@element = element
end
end
class Sheet < Element
include Enumerable
def each
@element.search('.//table:table-row').each do |e|
(e['number-rows-repeated'] || '1').to_i.times do
yield Row.new(e)
end
end
end
def rows
ary = []
each do |row|
ary << row
end
ary
end
def [](index)
rows[index]
end
end
class Row < Element
include Enumerable
def each
@element.search('.//table:table-cell').each do |e|
(e['number-columns-repeated'] || '1').to_i.times do
yield Cell.new(e)
end
end
end
def cells
ary = []
each do |cell|
ary << cell
end
ary
end
def [](index)
cells[index]
end
end
class Cell < Element
def value
@element.search('.//text:p').text
end
end
end
class ODSCSV
def self.open(filename, sheet_name, &block)
odscsv = self.new
odscsv.process_book(filename, sheet_name, &block)
end
def process_book(filename, sheet_name, &block)
ODS.open(filename) do |ods|
ws = ods.sheet(sheet_name)
process_sheet(ws, &block)
end
end
def process_sheet(sheet, &block)
sheet.each do |row|
process_row(row, &block)
end
end
def process_row(row, &block)
block.call(row.map do |cell|
cell.value
end)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment