roo 1.1.0 → 1.2.0

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