roo 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|