roo 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +11 -2
- data/README.txt +25 -11
- data/lib/roo/excel.rb +69 -22
- data/lib/roo/excelx.rb +181 -107
- data/lib/roo/generic_spreadsheet.rb +7 -13
- data/lib/roo/google.rb +3 -23
- data/lib/roo/openoffice.rb +9 -20
- data/lib/roo/version.rb +1 -1
- data/test/test_helper.rb +14 -8
- data/test/test_roo.rb +355 -227
- data/website/index.html +224 -437
- data/website/index.txt +28 -3
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,8 +1,17 @@
|
|
1
|
+
== 1.2.0 2008-08-24
|
2
|
+
* 3 major enhancements
|
3
|
+
* Excelx: improved the detection of cell type and conversion into roo types
|
4
|
+
* All: to_csv: changed boundaries from first_row,1..last_row,last_column to 1,1..last_row,last_column
|
5
|
+
* All: Environment variable "ROO_TMP" indicate where temporary directories will be created (if not set the default is the current working directory)
|
6
|
+
* 2 bugfixes
|
7
|
+
* Excel: improved the detection of last_row/last_column (parseexcel-gem bug?)
|
8
|
+
* Excel/Excelx/Openoffice: temporary directories were not removed at opening a file of the wrong type
|
1
9
|
== 1.1.0 2008-07-26
|
2
10
|
* 2 major enhancements
|
3
11
|
* Excel: speed improvements
|
4
|
-
* Changed the
|
5
|
-
*
|
12
|
+
* Changed the behavior of reading files with the wrong type
|
13
|
+
* 3 bugfixes
|
14
|
+
* Google: added normalize in set_value method
|
6
15
|
* Excel: last_row in Excel class did not work properly under some circumstances
|
7
16
|
* all: fixed a bug in #to_xml if there is an empty sheet
|
8
17
|
== 1.0.2 2008-07-04
|
data/README.txt
CHANGED
@@ -7,22 +7,36 @@ Installation:
|
|
7
7
|
|
8
8
|
Usage:
|
9
9
|
|
10
|
+
require 'rubygems'
|
10
11
|
require 'roo'
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
s = Openoffice.new("myspreadsheet.ods") # creates an Openoffice Spreadsheet instance
|
14
|
+
s = Excel.new("myspreadsheet.xls") # creates an Excel Spreadsheet instance
|
15
|
+
s = Google.new("myspreadsheetkey_at_google") # creates an Google Spreadsheet instance
|
16
|
+
s = Excelx.new("myspreadsheet.xlsx") # creates an Excel Spreadsheet instance for Excel .xlsx files
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
s.default_sheet = s.sheets.first # first sheet in the spreadsheet file will be used
|
19
|
+
|
20
|
+
# s.sheet is an array which holds the names of the sheets within
|
21
|
+
# a spreadsheet.
|
22
|
+
# you can also write
|
23
|
+
# s.default_sheet = s.sheets[3] or
|
24
|
+
# s.default_sheet = 'Sheet 3'
|
25
|
+
|
26
|
+
s.cell(1,1) # returns the content of the first row/first cell in the sheet
|
27
|
+
s.cell('A',1) # same cell
|
28
|
+
s.cell(1,'A') # same cell
|
29
|
+
s.cell(1,'A',s.sheets[0]) # same cell
|
30
|
+
|
31
|
+
# almost all methods have an optional argument 'sheet'.
|
32
|
+
# If this parameter is ommitted, the default_sheet will be used.
|
19
33
|
|
20
|
-
|
34
|
+
s.info # prints infos about the spreadsheet file
|
21
35
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
36
|
+
s.first_row # the number of the first row
|
37
|
+
s.last_row # the number of the last row
|
38
|
+
s.first_column # the number of the first column
|
39
|
+
s.last_column # the number of the last column
|
26
40
|
|
27
41
|
|
28
42
|
see http://roo.rubyforge.org for a more complete tutorial
|
data/lib/roo/excel.rb
CHANGED
@@ -24,18 +24,15 @@ class Excel < GenericSpreadsheet
|
|
24
24
|
super()
|
25
25
|
@file_warning = file_warning
|
26
26
|
@tmpdir = "oo_"+$$.to_s
|
27
|
+
@tmpdir = File.join(ENV['ROO_TMP'], @tmpdir) if ENV['ROO_TMP']
|
27
28
|
unless File.exists?(@tmpdir)
|
28
29
|
FileUtils::mkdir(@tmpdir)
|
29
30
|
end
|
30
31
|
filename = open_from_uri(filename) if filename[0,7] == "http://"
|
31
32
|
filename = unzip(filename) if packed and packed == :zip
|
32
|
-
#if File.extname(filename).downcase != ".xls"
|
33
|
-
# warn "are you sure, this is an excel file?"
|
34
|
-
#end
|
35
|
-
#@file_warning = :error
|
36
|
-
file_type_check(filename,'.xls','an Excel')
|
37
|
-
@filename = filename
|
38
33
|
begin
|
34
|
+
file_type_check(filename,'.xls','an Excel')
|
35
|
+
@filename = filename
|
39
36
|
unless File.file?(@filename)
|
40
37
|
raise IOError, "file #{@filename} does not exist"
|
41
38
|
end
|
@@ -45,9 +42,8 @@ class Excel < GenericSpreadsheet
|
|
45
42
|
if self.sheets.size == 1
|
46
43
|
@default_sheet = self.sheets.first
|
47
44
|
end
|
48
|
-
# @first_row = @last_row = @first_column = @last_column = nil
|
49
|
-
#if ENV["roo_local"] != "thomas-p"
|
50
45
|
ensure
|
46
|
+
#if ENV["roo_local"] != "thomas-p"
|
51
47
|
FileUtils::rm_r(@tmpdir)
|
52
48
|
#end
|
53
49
|
end
|
@@ -82,19 +78,6 @@ class Excel < GenericSpreadsheet
|
|
82
78
|
return result
|
83
79
|
end
|
84
80
|
|
85
|
-
#TODO: testing only
|
86
|
-
def inject_null_characters(str)
|
87
|
-
if str.class != String
|
88
|
-
return str
|
89
|
-
end
|
90
|
-
new_str=''
|
91
|
-
0.upto(str.size-1) do |i|
|
92
|
-
new_str += str[i,1]
|
93
|
-
new_str += "\000"
|
94
|
-
end
|
95
|
-
new_str
|
96
|
-
end
|
97
|
-
|
98
81
|
# returns the content of a cell. The upper left corner is (1,1) or ('A',1)
|
99
82
|
def cell(row,col,sheet=nil)
|
100
83
|
sheet = @default_sheet unless sheet
|
@@ -175,7 +158,7 @@ class Excel < GenericSpreadsheet
|
|
175
158
|
private
|
176
159
|
|
177
160
|
# determine the first and last boundaries
|
178
|
-
def
|
161
|
+
def get_firsts_lasts_parseexcel(sheet=nil)
|
179
162
|
sheet = @default_sheet unless sheet
|
180
163
|
fr = fc = 999_999
|
181
164
|
lr = lc = -999_999
|
@@ -212,6 +195,46 @@ class Excel < GenericSpreadsheet
|
|
212
195
|
end
|
213
196
|
end
|
214
197
|
# 2007-11-05 END
|
198
|
+
|
199
|
+
if lc
|
200
|
+
letzte_spalte_leer = true
|
201
|
+
until ! letzte_spalte_leer
|
202
|
+
worksheet.each(0) {|reihe|
|
203
|
+
if reihe
|
204
|
+
cell = reihe.at(lc-1)
|
205
|
+
if cell
|
206
|
+
case cell.type
|
207
|
+
when :numeric, :date
|
208
|
+
letzte_spalte_leer = false
|
209
|
+
when :text
|
210
|
+
letzte_spalte_leer = false if cell.to_s != ""
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
}
|
215
|
+
lc -= 1 if letzte_spalte_leer
|
216
|
+
#puts "letzte Spalte auf #{lc} verringert" if letzte_spalte_leer
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
return fr, lr, fc, lc
|
221
|
+
end
|
222
|
+
|
223
|
+
# determine the first and last boundaries
|
224
|
+
def get_firsts_lasts(sheet=nil)
|
225
|
+
fr,lr,fc,lc = get_firsts_lasts_parseexcel(sheet)
|
226
|
+
if lr
|
227
|
+
# 2007-11-05 BEGIN
|
228
|
+
# parsexcel liefert (mir unverstaendlich) eine Zeile als letzte Zeile
|
229
|
+
# zurueck, die aber leer ist. Deshalb Korrekturfunktion, die wirklich
|
230
|
+
# die letzte nicht leere Zeile liefert.
|
231
|
+
# 2008-07-23 meine Loesung funtionierte auch noch nicht unter allen
|
232
|
+
# Umstaenden row() == nil ergaenzt
|
233
|
+
while row(lr,sheet) == nil || empty_row?(row(lr,sheet))
|
234
|
+
lr -= 1
|
235
|
+
end
|
236
|
+
end
|
237
|
+
# 2007-11-05 END
|
215
238
|
@first_row[sheet] = fr
|
216
239
|
@last_row[sheet] = lr
|
217
240
|
@first_column[sheet] = fc
|
@@ -243,6 +266,16 @@ class Excel < GenericSpreadsheet
|
|
243
266
|
! content
|
244
267
|
end
|
245
268
|
|
269
|
+
def empty_column?(col)
|
270
|
+
content = false
|
271
|
+
col.compact.each {|elem|
|
272
|
+
if elem != ''
|
273
|
+
content = true
|
274
|
+
end
|
275
|
+
}
|
276
|
+
! content
|
277
|
+
end
|
278
|
+
|
246
279
|
def platform_specific_iconv(value)
|
247
280
|
case RUBY_PLATFORM.downcase
|
248
281
|
when /darwin/
|
@@ -360,4 +393,18 @@ class Excel < GenericSpreadsheet
|
|
360
393
|
@cells_read[sheet] = true
|
361
394
|
end
|
362
395
|
|
396
|
+
#TODO: testing only
|
397
|
+
# def inject_null_characters(str)
|
398
|
+
# if str.class != String
|
399
|
+
# return str
|
400
|
+
# end
|
401
|
+
# new_str=''
|
402
|
+
# 0.upto(str.size-1) do |i|
|
403
|
+
# new_str += str[i,1]
|
404
|
+
# new_str += "\000"
|
405
|
+
# end
|
406
|
+
# new_str
|
407
|
+
# end
|
408
|
+
#
|
409
|
+
|
363
410
|
end
|
data/lib/roo/excelx.rb
CHANGED
@@ -13,6 +13,70 @@ class String
|
|
13
13
|
end
|
14
14
|
|
15
15
|
class Excelx < GenericSpreadsheet
|
16
|
+
FORMATS = {
|
17
|
+
'General' => :float,
|
18
|
+
'0' => :float,
|
19
|
+
'0.00' => :float,
|
20
|
+
'#,##0' => :float,
|
21
|
+
'#,##0.00' => :float,
|
22
|
+
'0%' => :percentage,
|
23
|
+
'0.00%' => :percentage,
|
24
|
+
'0.00E+00' => :float,
|
25
|
+
'# ?/?' => :float, #??? TODO:
|
26
|
+
'# ??/??' => :float, #??? TODO:
|
27
|
+
'mm-dd-yy' => :date,
|
28
|
+
'd-mmm-yy' => :date,
|
29
|
+
'd-mmm' => :date,
|
30
|
+
'mmm-yy' => :date,
|
31
|
+
'h:mm AM/PM' => :date,
|
32
|
+
'h:mm:ss AM/PM' => :date,
|
33
|
+
'h:mm' => :time,
|
34
|
+
'h:mm:ss' => :time,
|
35
|
+
'm/d/yy h:mm' => :date,
|
36
|
+
'#,##0 ;(#,##0)' => :float,
|
37
|
+
'#,##0 ;[Red](#,##0)' => :float,
|
38
|
+
'#,##0.00;(#,##0.00)' => :float,
|
39
|
+
'#,##0.00;[Red](#,##0.00)' => :float,
|
40
|
+
'mm:ss' => :time,
|
41
|
+
'[h]:mm:ss' => :time,
|
42
|
+
'mmss.0' => :time,
|
43
|
+
'##0.0E+0' => :float,
|
44
|
+
'@' => :float,
|
45
|
+
#-- zusaetzliche Formate, die nicht standardmaessig definiert sind:
|
46
|
+
"yyyy\\-mm\\-dd" => :date,
|
47
|
+
'dd/mm/yy' => :date,
|
48
|
+
'hh:mm:ss' => :time,
|
49
|
+
}
|
50
|
+
STANDARD_FORMATS = {
|
51
|
+
0 => 'General',
|
52
|
+
1 => '0',
|
53
|
+
2 => '0.00',
|
54
|
+
3 => '#,##0',
|
55
|
+
4 => '#,##0.00',
|
56
|
+
9 => '0%',
|
57
|
+
10 => '0.00%',
|
58
|
+
11 => '0.00E+00',
|
59
|
+
12 => '# ?/?',
|
60
|
+
13 => '# ??/??',
|
61
|
+
14 => 'mm-dd-yy',
|
62
|
+
15 => 'd-mmm-yy',
|
63
|
+
16 => 'd-mmm',
|
64
|
+
17 => 'mmm-yy',
|
65
|
+
18 => 'h:mm AM/PM',
|
66
|
+
19 => 'h:mm:ss AM/PM',
|
67
|
+
20 => 'h:mm',
|
68
|
+
21 => 'h:mm:ss',
|
69
|
+
22 => 'm/d/yy h:mm',
|
70
|
+
37 => '#,##0 ;(#,##0)',
|
71
|
+
38 => '#,##0 ;[Red](#,##0)',
|
72
|
+
39 => '#,##0.00;(#,##0.00)',
|
73
|
+
40 => '#,##0.00;[Red](#,##0.00)',
|
74
|
+
45 => 'mm:ss',
|
75
|
+
46 => '[h]:mm:ss',
|
76
|
+
47 => 'mmss.0',
|
77
|
+
48 => '##0.0E+0',
|
78
|
+
49 => '@',
|
79
|
+
}
|
16
80
|
@@nr = 0
|
17
81
|
|
18
82
|
# initialization and opening of a spreadsheet file
|
@@ -21,19 +85,16 @@ class Excelx < GenericSpreadsheet
|
|
21
85
|
super()
|
22
86
|
@file_warning = file_warning
|
23
87
|
@tmpdir = "oo_"+$$.to_s
|
88
|
+
@tmpdir = File.join(ENV['ROO_TMP'], @tmpdir) if ENV['ROO_TMP']
|
24
89
|
unless File.exists?(@tmpdir)
|
25
90
|
FileUtils::mkdir(@tmpdir)
|
26
91
|
end
|
27
92
|
filename = open_from_uri(filename) if filename[0,7] == "http://"
|
28
93
|
filename = unzip(filename) if packed and packed == :zip
|
29
|
-
#if File.extname(filename).downcase != ".xlsx"
|
30
|
-
# warn "are you sure, this is an Excel-xlsx file?"
|
31
|
-
#end
|
32
|
-
#@file_warning = :error
|
33
|
-
file_type_check(filename,'.xlsx','an Excel-xlsx')
|
34
|
-
@cells_read = Hash.new
|
35
|
-
@filename = filename
|
36
94
|
begin
|
95
|
+
file_type_check(filename,'.xlsx','an Excel-xlsx')
|
96
|
+
@cells_read = Hash.new
|
97
|
+
@filename = filename
|
37
98
|
unless File.file?(@filename)
|
38
99
|
raise IOError, "file #{@filename} does not exist"
|
39
100
|
end
|
@@ -50,6 +111,13 @@ class Excelx < GenericSpreadsheet
|
|
50
111
|
file.close
|
51
112
|
read_shared_strings(@sharedstring_doc)
|
52
113
|
end
|
114
|
+
@styles_table = []
|
115
|
+
if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
|
116
|
+
file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
|
117
|
+
@styles_doc = REXML::Document.new file
|
118
|
+
file.close
|
119
|
+
read_styles(@styles_doc)
|
120
|
+
end
|
53
121
|
@sheet_doc = []
|
54
122
|
@sheet_files.each_with_index do |item, i|
|
55
123
|
file = File.new(item)
|
@@ -75,6 +143,8 @@ class Excelx < GenericSpreadsheet
|
|
75
143
|
@last_column = Hash.new
|
76
144
|
@header_line = 1
|
77
145
|
@excelx_type = Hash.new
|
146
|
+
@excelx_value = Hash.new
|
147
|
+
@s_attribute = Hash.new # TODO: ggf. wieder entfernen nur lokal benoetigt
|
78
148
|
end
|
79
149
|
|
80
150
|
# Returns the content of a spreadsheet-cell.
|
@@ -151,14 +221,34 @@ class Excelx < GenericSpreadsheet
|
|
151
221
|
end
|
152
222
|
end
|
153
223
|
|
154
|
-
# returns the internal type of
|
224
|
+
# returns the internal type of an excel cell
|
155
225
|
# * :numeric_or_formula
|
156
226
|
# * :string
|
227
|
+
# Note: this is only available within the Excelx class
|
157
228
|
def excelx_type(row,col,sheet=nil)
|
158
|
-
|
229
|
+
sheet = @default_sheet unless sheet
|
230
|
+
read_cells(sheet) unless @cells_read[sheet]
|
231
|
+
row,col = normalize(row,col)
|
232
|
+
return @excelx_type[sheet]["#{row},#{col}"]
|
233
|
+
end
|
234
|
+
|
235
|
+
# returns the internal value of an excelx cell
|
236
|
+
# Note: this is only available within the Excelx class
|
237
|
+
def excelx_value(row,col,sheet=nil)
|
238
|
+
sheet = @default_sheet unless sheet
|
239
|
+
read_cells(sheet) unless @cells_read[sheet]
|
240
|
+
row,col = normalize(row,col)
|
241
|
+
return @excelx_value[sheet]["#{row},#{col}"]
|
242
|
+
end
|
243
|
+
|
244
|
+
# returns the internal format of an excel cell
|
245
|
+
def excelx_format(row,col,sheet=nil)
|
246
|
+
sheet = @default_sheet unless sheet
|
159
247
|
read_cells(sheet) unless @cells_read[sheet]
|
160
248
|
row,col = normalize(row,col)
|
161
|
-
|
249
|
+
s = @s_attribute[sheet]["#{row},#{col}"]
|
250
|
+
result = attribute2format(s)
|
251
|
+
result
|
162
252
|
end
|
163
253
|
|
164
254
|
# returns an array of sheet names in the spreadsheet
|
@@ -204,7 +294,10 @@ class Excelx < GenericSpreadsheet
|
|
204
294
|
private
|
205
295
|
|
206
296
|
# helper function to set the internal representation of cells
|
207
|
-
def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v,
|
297
|
+
def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v,
|
298
|
+
excelx_type=nil,
|
299
|
+
excelx_value=nil,
|
300
|
+
s_attribute=nil)
|
208
301
|
key = "#{y},#{x+i}"
|
209
302
|
@cell_type[sheet] = {} unless @cell_type[sheet]
|
210
303
|
@cell_type[sheet][key] = vt
|
@@ -229,8 +322,13 @@ class Excelx < GenericSpreadsheet
|
|
229
322
|
end
|
230
323
|
@excelx_type[sheet] = {} unless @excelx_type[sheet]
|
231
324
|
@excelx_type[sheet][key] = excelx_type
|
325
|
+
@excelx_value[sheet] = {} unless @excelx_value[sheet]
|
326
|
+
@excelx_value[sheet][key] = excelx_value
|
327
|
+
@s_attribute[sheet] = {} unless @s_attribute[sheet]
|
328
|
+
@s_attribute[sheet][key] = s_attribute
|
232
329
|
end
|
233
330
|
|
331
|
+
# splits a coordinate like "AA12" into the parts "AA" (String) and 12 (Fixnum)
|
234
332
|
def split_coord(s)
|
235
333
|
letter = ""
|
236
334
|
number = 0
|
@@ -257,89 +355,20 @@ class Excelx < GenericSpreadsheet
|
|
257
355
|
end
|
258
356
|
|
259
357
|
# read all cells in the selected sheet
|
260
|
-
def
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
n = self.sheets.index(sheet)
|
266
|
-
@sheet_doc[n].each_element do |worksheet|
|
267
|
-
worksheet.each_element do |elem|
|
268
|
-
if elem.name == 'sheetData'
|
269
|
-
elem.each_element do |sheetdata|
|
270
|
-
if sheetdata.name == 'row'
|
271
|
-
sheetdata.each_element do |row|
|
272
|
-
if row.name == 'c'
|
273
|
-
if row.attributes['t'] == 's'
|
274
|
-
tmp_type = :shared
|
275
|
-
end
|
276
|
-
if row.attributes['s'] == '2' #or
|
277
|
-
#row.attributes['s'] == '1' # 2008-07-26
|
278
|
-
tmp_type = :time
|
279
|
-
elsif row.attributes['s'] == '1' and row.attributes['t'] == nil # and ergaenzt 2008-07-03
|
280
|
-
tmp_type = :formula
|
281
|
-
end
|
282
|
-
formula = nil
|
283
|
-
f_element_found = false
|
284
|
-
row.each_element do |cell|
|
285
|
-
if cell.name == 'f'
|
286
|
-
f_element_found = true
|
287
|
-
formula = cell.text
|
288
|
-
end
|
289
|
-
if cell.name == 'v'
|
290
|
-
if tmp_type == :formula and f_element_found == false
|
291
|
-
#if cell.text.to_f < 1.0 # 2008-07-26
|
292
|
-
tmp_type = :time
|
293
|
-
#else # 2008-07-26
|
294
|
-
#tmp_type = :date #2008-07-26
|
295
|
-
#end #2008-07-26
|
296
|
-
end
|
297
|
-
if tmp_type == :time #2008-07-26
|
298
|
-
if cell.text.to_f >= 1.0 # 2008-07-26
|
299
|
-
tmp_type = :date # 2008-07-26
|
300
|
-
end # 2008-07-26
|
301
|
-
end # 2008-07-26
|
302
|
-
if tmp_type == :shared
|
303
|
-
vt = :string
|
304
|
-
str_v = @shared_table[cell.text.to_i]
|
305
|
-
elsif tmp_type == :date
|
306
|
-
vt = :date
|
307
|
-
v = cell.text
|
308
|
-
elsif tmp_type == :time
|
309
|
-
vt = :time
|
310
|
-
v = cell.text
|
311
|
-
elsif tmp_type == :formula
|
312
|
-
vt = :formula
|
313
|
-
v = cell.text.to_f #TODO: !!!!
|
314
|
-
else
|
315
|
-
vt = :float
|
316
|
-
v = cell.text
|
317
|
-
end
|
318
|
-
x,y = split_coordinate(row.attributes['r'])
|
319
|
-
tr=nil #TODO: ???s
|
320
|
-
set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v)
|
321
|
-
end
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
329
|
-
end
|
330
|
-
sheet_found = true #TODO:
|
331
|
-
if !sheet_found
|
332
|
-
raise RangeError
|
358
|
+
def format2type(format)
|
359
|
+
if FORMATS.has_key? format
|
360
|
+
FORMATS[format]
|
361
|
+
else
|
362
|
+
:float
|
333
363
|
end
|
334
|
-
@cells_read[sheet] = true
|
335
364
|
end
|
336
365
|
|
337
|
-
# read all cells in the selected sheet
|
366
|
+
# read all cells in the selected sheet
|
338
367
|
def read_cells(sheet=nil)
|
339
368
|
sheet = @default_sheet unless sheet
|
340
369
|
sheet_found = false
|
341
370
|
raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
|
342
|
-
|
371
|
+
raise RangeError unless self.sheets.include? sheet
|
343
372
|
n = self.sheets.index(sheet)
|
344
373
|
@sheet_doc[n].each_element do |worksheet|
|
345
374
|
worksheet.each_element do |elem|
|
@@ -350,34 +379,24 @@ class Excelx < GenericSpreadsheet
|
|
350
379
|
if row.name == 'c'
|
351
380
|
if row.attributes['t'] == 's'
|
352
381
|
tmp_type = :shared
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
tmp_type =
|
357
|
-
elsif row.attributes['s'] == '1' and row.attributes['t'] == nil # and ergaenzt 2008-07-03
|
358
|
-
tmp_type = :formula
|
382
|
+
else
|
383
|
+
s_attribute = row.attributes['s']
|
384
|
+
format = attribute2format(s_attribute)
|
385
|
+
tmp_type = format2type(format)
|
359
386
|
end
|
360
387
|
formula = nil
|
361
|
-
f_element_found = false
|
362
388
|
row.each_element do |cell|
|
363
389
|
if cell.name == 'f'
|
364
|
-
f_element_found = true
|
365
390
|
formula = cell.text
|
366
391
|
end
|
367
392
|
if cell.name == 'v'
|
368
|
-
if tmp_type == :formula and f_element_found == false
|
369
|
-
#if cell.text.to_f < 1.0 # 2008-07-26
|
370
|
-
tmp_type = :time
|
371
|
-
#else # 2008-07-26
|
372
|
-
#tmp_type = :date #2008-07-26
|
373
|
-
#end #2008-07-26
|
374
|
-
end
|
375
393
|
if tmp_type == :time #2008-07-26
|
376
394
|
if cell.text.to_f >= 1.0 # 2008-07-26
|
377
395
|
tmp_type = :date # 2008-07-26
|
378
396
|
end # 2008-07-26
|
379
397
|
end # 2008-07-26
|
380
|
-
excelx_type = :numeric_or_formula
|
398
|
+
excelx_type = [:numeric_or_formula,format]
|
399
|
+
excelx_value = cell.text
|
381
400
|
if tmp_type == :shared
|
382
401
|
vt = :string
|
383
402
|
str_v = @shared_table[cell.text.to_i]
|
@@ -397,7 +416,7 @@ class Excelx < GenericSpreadsheet
|
|
397
416
|
end
|
398
417
|
x,y = split_coordinate(row.attributes['r'])
|
399
418
|
tr=nil #TODO: ???s
|
400
|
-
set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,excelx_type)
|
419
|
+
set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,excelx_type,excelx_value,s_attribute)
|
401
420
|
end
|
402
421
|
end
|
403
422
|
end
|
@@ -413,7 +432,7 @@ class Excelx < GenericSpreadsheet
|
|
413
432
|
end
|
414
433
|
@cells_read[sheet] = true
|
415
434
|
end
|
416
|
-
|
435
|
+
|
417
436
|
# Checks if the default_sheet exists. If not an RangeError exception is
|
418
437
|
# raised
|
419
438
|
def check_default_sheet
|
@@ -435,7 +454,7 @@ class Excelx < GenericSpreadsheet
|
|
435
454
|
end
|
436
455
|
end
|
437
456
|
|
438
|
-
|
457
|
+
# extracts all needed files from the zip file
|
439
458
|
def process_zipfile(zipfilename, zip, path='')
|
440
459
|
@sheet_files = []
|
441
460
|
Zip::ZipFile.open(zipfilename) {|zf|
|
@@ -451,9 +470,13 @@ class Excelx < GenericSpreadsheet
|
|
451
470
|
f << zip.read(entry)
|
452
471
|
}
|
453
472
|
end
|
473
|
+
if entry.to_s.end_with?('styles.xml')
|
474
|
+
open(@tmpdir+'/'+@file_nr.to_s+'_roo_styles.xml','wb') {|f|
|
475
|
+
f << zip.read(entry)
|
476
|
+
}
|
477
|
+
end
|
454
478
|
if entry.to_s =~ /sheet([0-9]+).xml$/
|
455
479
|
nr = $1
|
456
|
-
# entry.extract("xaxa_sheet#{nr}.xml")
|
457
480
|
open(@tmpdir+'/'+@file_nr.to_s+"_roo_sheet#{nr}",'wb') {|f|
|
458
481
|
f << zip.read(entry)
|
459
482
|
}
|
@@ -464,22 +487,26 @@ class Excelx < GenericSpreadsheet
|
|
464
487
|
return
|
465
488
|
end
|
466
489
|
|
490
|
+
# extract files from the zip file
|
467
491
|
def extract_content(zipfilename)
|
468
492
|
Zip::ZipFile.open(@filename) do |zip|
|
469
493
|
process_zipfile(zipfilename,zip)
|
470
494
|
end
|
471
495
|
end
|
472
496
|
|
497
|
+
# sets the value of a cell
|
473
498
|
def set_value(row,col,value,sheet=nil)
|
474
499
|
sheet = @default_value unless sheet
|
475
500
|
@cell[sheet]["#{row},#{col}"] = value
|
476
501
|
end
|
477
502
|
|
503
|
+
# sets the type of a cell
|
478
504
|
def set_type(row,col,type,sheet=nil)
|
479
505
|
sheet = @default_value unless sheet
|
480
506
|
@cell_type[sheet]["#{row},#{col}"] = type
|
481
507
|
end
|
482
508
|
|
509
|
+
# read the shared strings xml document
|
483
510
|
def read_shared_strings(doc)
|
484
511
|
doc.each_element do |sst|
|
485
512
|
if sst.name == 'sst'
|
@@ -496,4 +523,51 @@ class Excelx < GenericSpreadsheet
|
|
496
523
|
end
|
497
524
|
end
|
498
525
|
|
526
|
+
# read the styles elements of an excelx document
|
527
|
+
def read_styles(doc)
|
528
|
+
@numFmts = []
|
529
|
+
@cellXfs = []
|
530
|
+
doc.each_element do |e1|
|
531
|
+
if e1.name == "styleSheet"
|
532
|
+
e1.each_element do |e2|
|
533
|
+
if e2.name == "numFmts"
|
534
|
+
e2.each_element do |e3|
|
535
|
+
if e3.name == 'numFmt'
|
536
|
+
numFmtId = e3.attributes['numFmtId']
|
537
|
+
formatCode = e3.attributes['formatCode']
|
538
|
+
@numFmts << [numFmtId, formatCode]
|
539
|
+
end
|
540
|
+
end
|
541
|
+
elsif e2.name == "cellXfs"
|
542
|
+
e2.each_element do |e3|
|
543
|
+
if e3.name == 'xf'
|
544
|
+
numFmtId = e3.attributes['numFmtId']
|
545
|
+
# p numFmtId
|
546
|
+
@cellXfs << [numFmtId]
|
547
|
+
end
|
548
|
+
end
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
# convert internal excelx attribute to a format
|
556
|
+
def attribute2format(s)
|
557
|
+
result = nil
|
558
|
+
@numFmts.each {|nf|
|
559
|
+
if nf.first == @cellXfs[s.to_i].first
|
560
|
+
result = nf[1]
|
561
|
+
break
|
562
|
+
end
|
563
|
+
}
|
564
|
+
unless result
|
565
|
+
id = @cellXfs[s.to_i].first.to_i
|
566
|
+
if STANDARD_FORMATS.has_key? id
|
567
|
+
result = STANDARD_FORMATS[id]
|
568
|
+
end
|
569
|
+
end
|
570
|
+
result
|
571
|
+
end
|
572
|
+
|
499
573
|
end # class
|