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.
@@ -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 behaviour of reading files with the false type
5
- * 2 bugfixex
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
- sob = Openoffice("myspreadsheet.ods") # creates an Openoffice Spreadsheet instance
13
- sob = Excel("myspreadsheet.xls") # creates an Excel Spreadsheet instance
14
- sob = Google("myspreadsheetkey_at_google") # creates an Google Spreadsheet instance
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
- sob.default_sheet = sob.sheets.first # first sheet in the spreadsheet file will be used
17
- sob.cell(1,1) # returns the content of the first row/first cell in the sheet
18
- sob.cell('A',1) # same cell
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
- sob.info # prints infos about the spreadsheet file
34
+ s.info # prints infos about the spreadsheet file
21
35
 
22
- sob.first_row # the number of the first row
23
- sob.last_row # the number of the last row
24
- sob.first_column # the number of the first column
25
- sob.last_column # the number of the last column
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
@@ -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 get_firsts_lasts(sheet=nil)
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
@@ -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 a excel cell
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
- sheet = @default_sheet unless sheet
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
- :numeric_or_formula
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,excelx_type=nil)
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 ALTER_ANSATZ_read_cells(sheet=nil)
261
- sheet = @default_sheet unless sheet
262
- sheet_found = false
263
- raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
264
- raise RangeError unless self.sheets.include? sheet
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
- raise RangeError unless self.sheets.include? sheet
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
- end
354
- if row.attributes['s'] == '2' #or
355
- #row.attributes['s'] == '1' # 2008-07-26
356
- tmp_type = :time
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