roo 1.2.3 → 1.3.5

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,11 +1,17 @@
1
- README for roo
2
- ==============
1
+ # README for Roo
3
2
 
4
- Installation:
3
+ This is now the official roo repository and I'll be making a release on RubyForge in the next few weeks.
5
4
 
6
- sudo gem install roo
7
5
 
8
- Usage:
6
+ ## Installation
7
+
8
+ # Run the following if you haven't done so before:
9
+ gem sources -a http://gems.github.com/
10
+
11
+ # Install the gem:
12
+ sudo gem install hmcgowan-roo
13
+
14
+ ## Usage:
9
15
 
10
16
  require 'rubygems'
11
17
  require 'roo'
@@ -1,16 +1,33 @@
1
- require 'rubygems'
2
- gem 'parseexcel', '>= 0.5.2'
3
- require 'parseexcel'
4
- CHARGUESS = false
5
- require 'charguess' if CHARGUESS
1
+ require 'spreadsheet'
2
+ CHARGUESS = begin
3
+ require 'charguess'
4
+ true
5
+ rescue LoadError => e
6
+ false
7
+ end
6
8
 
7
- module Spreadsheet # :nodoc
8
- module ParseExcel
9
- class Worksheet
10
- include Enumerable
11
- attr_reader :min_row, :max_row, :min_col, :max_col
12
- end
9
+ # ruby-spreadsheet has a font object so we're extending it
10
+ # with our own functionality but still providing full access
11
+ # to the user for other font information
12
+ module ExcelFontExtensions
13
+ def bold?(*args)
14
+ #From ruby-spreadsheet doc: 100 <= weight <= 1000, bold => 700, normal => 400
15
+ case weight
16
+ when 700
17
+ true
18
+ else
19
+ false
20
+ end
21
+ end
22
+
23
+ def italic?
24
+ italic
13
25
  end
26
+
27
+ def underline?
28
+ underline != :none
29
+ end
30
+
14
31
  end
15
32
 
16
33
  # Class for handling Excel-Spreadsheets
@@ -37,7 +54,7 @@ class Excel < GenericSpreadsheet
37
54
  unless File.file?(@filename)
38
55
  raise IOError, "file #{@filename} does not exist"
39
56
  end
40
- @workbook = Spreadsheet::ParseExcel.parse(filename)
57
+ @workbook = Spreadsheet.open(filename)
41
58
  @default_sheet = nil
42
59
  # no need to set default_sheet if there is only one sheet in the document
43
60
  if self.sheets.size == 1
@@ -57,25 +74,14 @@ class Excel < GenericSpreadsheet
57
74
  @last_column = Hash.new
58
75
  @header_line = 1
59
76
  @cells_read = Hash.new
77
+ @fonts = Hash.new
60
78
  end
61
79
 
62
80
  # returns an array of sheet names in the spreadsheet
63
81
  def sheets
64
82
  result = []
65
- #0.upto(@workbook.worksheets.size - 1) do |i| # spreadsheet
66
- 0.upto(@workbook.sheet_count - 1) do |i| # parseexcel
67
- # TODO: is there a better way to do conversion?
68
- if CHARGUESS
69
- encoding = CharGuess::guess(@workbook.worksheet(i).name)
70
- encoding = 'unicode' unless encoding
71
-
72
-
73
- result << Iconv.new('utf-8',encoding).iconv(
74
- @workbook.worksheet(i).name
75
- )
76
- else
77
- result << platform_specific_iconv(@workbook.worksheet(i).name)
78
- end
83
+ @workbook.worksheets.each do |worksheet|
84
+ result << normalize_string(worksheet.name)
79
85
  end
80
86
  return result
81
87
  end
@@ -169,6 +175,14 @@ class Excel < GenericSpreadsheet
169
175
  raise EXCEL_NO_FORMULAS
170
176
  end
171
177
 
178
+ # Given a cell, return the cell's font
179
+ def font(row, col, sheet=nil)
180
+ sheet = @default_sheet unless sheet
181
+ read_cells(sheet) unless @cells_read[sheet]
182
+ row,col = normalize(row,col)
183
+ @fonts[sheet][[row,col]]
184
+ end
185
+
172
186
  # shows the internal representation of all cells
173
187
  # mainly for debugging purposes
174
188
  def to_s(sheet=nil)
@@ -218,14 +232,10 @@ class Excel < GenericSpreadsheet
218
232
  # converts name of a sheet to index (0,1,2,..)
219
233
  def sheet_no(name)
220
234
  return name-1 if name.kind_of?(Fixnum)
221
- 0.upto(@workbook.sheet_count - 1) do |i|
222
- #0.upto(@workbook.worksheets.size - 1) do |i|
223
- # TODO: is there a better way to do conversion?
224
- return i if name == platform_specific_iconv(
225
- @workbook.worksheet(i).name)
226
- #Iconv.new('utf-8','unicode').iconv(
227
- # @workbook.worksheet(i).name
228
- # )
235
+ i = 0
236
+ @workbook.worksheets.each do |worksheet|
237
+ return i if name == normalize_string(worksheet.name)
238
+ i += 1
229
239
  end
230
240
  raise StandardError, "sheet '#{name}' not found"
231
241
  end
@@ -249,7 +259,16 @@ class Excel < GenericSpreadsheet
249
259
  }
250
260
  ! content
251
261
  end
252
-
262
+
263
+ def normalize_string(value)
264
+ value = every_second_null?(value) ? remove_every_second_null(value) : value
265
+ if CHARGUESS && encoding = CharGuess::guess(value)
266
+ Iconv.new('utf-8', encoding)
267
+ else
268
+ platform_specific_iconv(value)
269
+ end
270
+ end
271
+
253
272
  def platform_specific_iconv(value)
254
273
  case RUBY_PLATFORM.downcase
255
274
  when /darwin/
@@ -291,19 +310,22 @@ class Excel < GenericSpreadsheet
291
310
  end
292
311
 
293
312
  # helper function to set the internal representation of cells
294
- def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v)
313
+ def set_cell_values(sheet,row,col,i,v,vt,formula,tr,font)
295
314
  #key = "#{y},#{x+i}"
296
- key = [y,x+i]
315
+ key = [row,col+i]
297
316
  @cell_type[sheet] = {} unless @cell_type[sheet]
298
317
  @cell_type[sheet][key] = vt
299
318
  @formula[sheet] = {} unless @formula[sheet]
300
319
  @formula[sheet][key] = formula if formula
301
320
  @cell[sheet] = {} unless @cell[sheet]
321
+ @fonts[sheet] = {} unless @fonts[sheet]
322
+ @fonts[sheet][key] = font
323
+
302
324
  case vt # @cell_type[sheet][key]
303
325
  when :float
304
326
  @cell[sheet][key] = v.to_f
305
327
  when :string
306
- @cell[sheet][key] = str_v
328
+ @cell[sheet][key] = v
307
329
  when :date
308
330
  @cell[sheet][key] = v
309
331
  when :datetime
@@ -328,63 +350,90 @@ class Excel < GenericSpreadsheet
328
350
  end
329
351
 
330
352
  worksheet = @workbook.worksheet(sheet_no(sheet))
331
- skip = 0
332
- x =1
333
- y=1
334
- i=0
335
- worksheet.each(skip) { |row_par|
336
- if row_par
337
- x =1
338
- row_par.each do # |void|
339
- cell = row_par.at(x-1)
340
- if cell
341
- case cell.type
342
- when :numeric
343
- vt = :float
344
- v = cell.to_f
345
- when :text
346
- vt = :string
347
- str_v = cell.to_s('utf-8')
348
- when :date
349
- if cell.to_s.to_f < 1.0
350
- vt = :time
351
- f = cell.to_s.to_f*24.0*60.0*60.0
352
- secs = f.round
353
- h = (secs / 3600.0).floor
354
- secs = secs - 3600*h
355
- m = (secs / 60.0).floor
356
- secs = secs - 60*m
357
- s = secs
358
- v = h*3600+m*60+s
359
- else
360
- if cell.datetime.hour != 0 or
361
- cell.datetime.min != 0 or
362
- cell.datetime.sec != 0 or
363
- cell.datetime.msec != 0
364
- vt = :datetime
365
- v = cell.datetime
366
- else
367
- vt = :date
368
- v = cell.date
369
- v = sprintf("%04d-%02d-%02d",v.year,v.month,v.day)
370
- end
371
- end
372
- else
373
- vt = cell.type.to_s.downcase.to_sym
374
- v = nil
375
- end # case
376
- formula = tr = nil #TODO:???
377
- set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v)
378
- end # if cell
379
-
380
- x += 1
353
+ row_index=1
354
+ worksheet.each(0) do |row|
355
+ (0..row.size).each do |cell_index|
356
+ cell = row.at(cell_index)
357
+ next if cell.nil? #skip empty cells
358
+ next if cell.class == Spreadsheet::Formula
359
+ if date_or_time?(row, cell_index)
360
+ vt, v = read_cell_date_or_time(row, cell_index)
361
+ else
362
+ vt, v = read_cell(row, cell_index)
381
363
  end
382
- end
383
- y += 1
384
- }
364
+ formula = tr = nil #TODO:???
365
+ col_index = cell_index + 1
366
+ font = row.format(cell_index).font
367
+ font.extend(ExcelFontExtensions)
368
+ set_cell_values(sheet,row_index,col_index,0,v,vt,formula,tr,font)
369
+ end #row
370
+ row_index += 1
371
+ end # worksheet
385
372
  @cells_read[sheet] = true
386
373
  end
387
-
374
+
375
+ # Test the cell to see if it's a valid date/time.
376
+ def date_or_time?(row, idx)
377
+ format = row.format(idx)
378
+ if format.date_or_time?
379
+ cell = row.at(idx)
380
+ true if Float(cell) > 0 rescue false
381
+ else
382
+ false
383
+ end
384
+ end
385
+ private :date_or_time?
386
+
387
+ # Read the date-time cell and convert to,
388
+ # the date-time values for Roo
389
+ def read_cell_date_or_time(row, idx)
390
+ cell = row.at(idx).to_s.to_f
391
+ if cell < 1.0
392
+ value_type = :time
393
+ f = cell*24.0*60.0*60.0
394
+ secs = f.round
395
+ h = (secs / 3600.0).floor
396
+ secs = secs - 3600*h
397
+ m = (secs / 60.0).floor
398
+ secs = secs - 60*m
399
+ s = secs
400
+ value = h*3600+m*60+s
401
+ else
402
+ datetime = row.datetime(idx)
403
+ if datetime.hour != 0 or
404
+ datetime.min != 0 or
405
+ datetime.sec != 0
406
+ value_type = :datetime
407
+ value = datetime
408
+ else
409
+ value_type = :date
410
+ value = row.date(idx)
411
+ value = sprintf("%04d-%02d-%02d",value.year,value.month,value.day)
412
+ end
413
+ end
414
+ return value_type, value
415
+ end
416
+ private :read_cell_date_or_time
417
+
418
+ # Read the cell and based on the class,
419
+ # return the values for Roo
420
+ def read_cell(row, idx)
421
+ cell = row.at(idx)
422
+ case cell
423
+ when Float, Integer, Fixnum, Bignum
424
+ value_type = :float
425
+ value = cell.to_f
426
+ when String, TrueClass, FalseClass
427
+ value_type = :string
428
+ value = cell.to_s
429
+ else
430
+ value_type = cell.class.to_s.downcase.to_sym
431
+ value = nil
432
+ end # case
433
+ return value_type, value
434
+ end
435
+ private :read_cell
436
+
388
437
  #TODO: testing only
389
438
  # def inject_null_characters(str)
390
439
  # if str.class != String
@@ -1,6 +1,4 @@
1
-
2
- require 'rubygems'
3
- require 'rexml/document'
1
+ require 'xml'
4
2
  require 'fileutils'
5
3
  require 'zip/zipfilesystem'
6
4
  require 'date'
@@ -102,26 +100,27 @@ class Excelx < GenericSpreadsheet
102
100
  @file_nr = @@nr
103
101
  extract_content(@filename)
104
102
  file = File.new(File.join(@tmpdir, @file_nr.to_s+"_roo_workbook.xml"))
105
- @workbook_doc = REXML::Document.new file
103
+ @workbook_doc = XML::Parser.io(file).parse
106
104
  file.close
107
105
  @shared_table = []
108
106
  if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml'))
109
107
  file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml'))
110
- @sharedstring_doc = REXML::Document.new file
108
+ @sharedstring_doc = XML::Parser.io(file).parse
111
109
  file.close
112
110
  read_shared_strings(@sharedstring_doc)
113
111
  end
114
112
  @styles_table = []
113
+ @style_definitions = Array.new { |h,k| h[k] = {} }
115
114
  if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
116
115
  file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
117
- @styles_doc = REXML::Document.new file
116
+ @styles_doc = XML::Parser.io(file).parse
118
117
  file.close
119
118
  read_styles(@styles_doc)
120
119
  end
121
120
  @sheet_doc = []
122
121
  @sheet_files.each_with_index do |item, i|
123
122
  file = File.new(item)
124
- @sheet_doc[i] = REXML::Document.new file
123
+ @sheet_doc[i] = XML::Parser.io(file).parse
125
124
  file.close
126
125
  end
127
126
  ensure
@@ -163,7 +162,6 @@ class Excelx < GenericSpreadsheet
163
162
  yyyy,mm,dd = date_part.split('-')
164
163
  hh,mi,ss = time_part.split(':')
165
164
  return DateTime.civil(yyyy.to_i,mm.to_i,dd.to_i,hh.to_i,mi.to_i,ss.to_i)
166
-
167
165
  end
168
166
  @cell[sheet][[row,col]]
169
167
  end
@@ -189,6 +187,33 @@ class Excelx < GenericSpreadsheet
189
187
  row,col = normalize(row,col)
190
188
  formula(row,col) != nil
191
189
  end
190
+
191
+ class Font
192
+ attr_accessor :bold, :italic, :underline
193
+
194
+ def bold?
195
+ @bold == true
196
+ end
197
+
198
+ def italic?
199
+ @italic == true
200
+ end
201
+
202
+ def underline?
203
+ @underline == true
204
+ end
205
+ end
206
+
207
+ # Given a cell, return the cell's style
208
+ def font(row, col, sheet=nil)
209
+ sheet = @default_sheet unless sheet
210
+ read_cells(sheet) unless @cells_read[sheet]
211
+ row,col = normalize(row,col)
212
+ s_attribute = @s_attribute[sheet][[row,col]]
213
+ s_attribute ||= 0
214
+ s_attribute = s_attribute.to_i
215
+ @style_definitions[s_attribute]
216
+ end
192
217
 
193
218
  # set a cell to a certain value
194
219
  # (this will not be saved back to the spreadsheet file!)
@@ -260,18 +285,11 @@ class Excelx < GenericSpreadsheet
260
285
  # returns an array of sheet names in the spreadsheet
261
286
  def sheets
262
287
  return_sheets = []
263
- @workbook_doc.each_element do |workbook|
264
- workbook.each_element do |el|
265
- if el.name == "sheets"
266
- el.each_element do |sheet|
267
- return_sheets << sheet.attributes['name']
268
- end
269
- end
270
- end
288
+ @workbook_doc.find("//*[local-name()='sheet']").each do |sheet|
289
+ return_sheets << sheet.attributes.to_h['name']
271
290
  end
272
291
  return_sheets
273
292
  end
274
-
275
293
  # shows the internal representation of all cells
276
294
  # for debugging purposes
277
295
  def to_s(sheet=nil)
@@ -376,82 +394,62 @@ class Excelx < GenericSpreadsheet
376
394
  raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
377
395
  raise RangeError unless self.sheets.include? sheet
378
396
  n = self.sheets.index(sheet)
379
- @sheet_doc[n].each_element do |worksheet|
380
- worksheet.each_element do |elem|
381
- if elem.name == 'sheetData'
382
- elem.each_element do |sheetdata|
383
- if sheetdata.name == 'row'
384
- sheetdata.each_element do |row|
385
- if row.name == 'c'
386
- if row.attributes['t'] == 's'
387
- tmp_type = :shared
388
- else
389
- s_attribute = row.attributes['s']
390
- format = attribute2format(s_attribute)
391
- tmp_type = format2type(format)
392
- end
393
- formula = nil
394
- row.each_element do |cell|
395
- # puts "cell.name: #{cell.name}" if cell.text.include? "22606.5120"
396
- # puts "cell.text: #{cell.text}" if cell.text.include? "22606.5120"
397
- if cell.name == 'f'
398
- formula = cell.text
399
- end
400
- if cell.name == 'v'
401
- #puts "tmp_type: #{tmp_type}" if cell.text.include? "22606.5120"
402
- #puts cell.name
403
- if tmp_type == :time or tmp_type == :datetime #2008-07-26
404
- #p cell.text
405
- # p cell.text.to_f if cell.text.include? "22606.5120"
406
- if cell.text.to_f >= 1.0 # 2008-07-26
407
- # puts ">= 1.0" if cell.text.include? "22606.5120"
408
- # puts "cell.text.to_f: #{cell.text.to_f}" if cell.text.include? "22606.5120"
409
- #puts "cell.text.to_f.floor: #{cell.text.to_f.floor}" if cell.text.include? "22606.5120"
410
- if (cell.text.to_f - cell.text.to_f.floor).abs > 0.000001 #TODO:
411
- # puts "abs ist groesser" if cell.text.include? "22606.5120"
412
- # @cell[sheet][key] = DateTime.parse(tr.attributes['date-value'])
413
- tmp_type = :datetime
414
-
415
- else
416
- #puts ":date"
417
- tmp_type = :date # 2008-07-26
418
- end
419
- else
420
- #puts "<1.0"
421
- end # 2008-07-26
422
- end # 2008-07-26
423
- excelx_type = [:numeric_or_formula,format]
424
- excelx_value = cell.text
425
- if tmp_type == :shared
426
- vt = :string
427
- str_v = @shared_table[cell.text.to_i]
428
- excelx_type = :string
429
- elsif tmp_type == :date
430
- vt = :date
431
- v = cell.text
432
- elsif tmp_type == :time
433
- vt = :time
434
- v = cell.text
435
- elsif tmp_type == :datetime
436
- vt = :datetime
437
- v = cell.text
438
- elsif tmp_type == :formula
439
- vt = :formula
440
- v = cell.text.to_f #TODO: !!!!
441
- else
442
- vt = :float
443
- v = cell.text
444
- end
445
- #puts "vt: #{vt}" if cell.text.include? "22606.5120"
446
- x,y = split_coordinate(row.attributes['r'])
447
- tr=nil #TODO: ???s
448
- set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,excelx_type,excelx_value,s_attribute)
449
- end
450
- end
451
- end
397
+ @sheet_doc[n].find("//*[local-name()='c']").each do |c|
398
+ s_attribute = c.attributes.to_h['s'].to_i # should be here
399
+ if (c.attributes.to_h['t'] == 's')
400
+ tmp_type = :shared
401
+ elsif (c.attributes.to_h['t'] == 'b')
402
+ tmp_type = :boolean
403
+ else
404
+ # s_attribute = c.attributes.to_h['s'].to_i # was here
405
+ format = attribute2format(s_attribute)
406
+ tmp_type = format2type(format)
407
+ end
408
+ formula = nil
409
+ c.each_element do |cell|
410
+ if cell.name == 'f'
411
+ formula = cell.content
412
+ end
413
+ if cell.name == 'v'
414
+ if tmp_type == :time or tmp_type == :datetime
415
+ if cell.content.to_f >= 1.0
416
+ if (cell.content.to_f - cell.content.to_f.floor).abs > 0.000001
417
+ tmp_type = :datetime
418
+ else
419
+ tmp_type = :date
452
420
  end
453
- end
421
+ else
422
+ end
423
+ end
424
+ excelx_type = [:numeric_or_formula,format]
425
+ excelx_value = cell.content
426
+ if tmp_type == :shared
427
+ vt = :string
428
+ str_v = @shared_table[cell.content.to_i]
429
+ excelx_type = :string
430
+ elsif tmp_type == :boolean
431
+ vt = :boolean
432
+ cell.content.to_i == 1 ? v = 'TRUE' : v = 'FALSE'
433
+ elsif tmp_type == :date
434
+ vt = :date
435
+ v = cell.content
436
+ elsif tmp_type == :time
437
+ vt = :time
438
+ v = cell.content
439
+ elsif tmp_type == :datetime
440
+ vt = :datetime
441
+ v = cell.content
442
+ elsif tmp_type == :formula
443
+ vt = :formula
444
+ v = cell.content.to_f #TODO: !!!!
445
+ else
446
+ vt = :float
447
+ v = cell.content
454
448
  end
449
+ #puts "vt: #{vt}" if cell.text.include? "22606.5120"
450
+ x,y = split_coordinate(c.attributes.to_h['r'])
451
+ tr=nil #TODO: ???s
452
+ set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,excelx_type,excelx_value,s_attribute)
455
453
  end
456
454
  end
457
455
  end
@@ -467,17 +465,9 @@ class Excelx < GenericSpreadsheet
467
465
  def check_default_sheet
468
466
  sheet_found = false
469
467
  raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil
470
- @workbook_doc.each_element do |workbook|
471
- workbook.each_element do |el|
472
- if el.name == "sheets"
473
- el.each_element do |sheet|
474
- if @default_sheet == sheet.attributes['name']
475
- sheet_found = true
476
- end
477
- end
478
- end
479
- end
480
- end
468
+
469
+ sheet_found = true if sheets.include?(@default_sheet)
470
+
481
471
  if ! sheet_found
482
472
  raise RangeError, "sheet '#{@default_sheet}' not found"
483
473
  end
@@ -537,18 +527,21 @@ class Excelx < GenericSpreadsheet
537
527
 
538
528
  # read the shared strings xml document
539
529
  def read_shared_strings(doc)
540
- doc.each_element do |sst|
541
- if sst.name == 'sst'
542
- sst.each_element do |si|
543
- if si.name == 'si'
544
- si.each_element do |elem|
545
- if elem.name == 't'
546
- @shared_table << elem.text
547
- end
530
+ doc.find("//*[local-name()='si']").each do |si|
531
+ shared_table_entry = ''
532
+ si.each_element do |elem|
533
+ if (elem.name == 'r')
534
+ elem.each_element do |r_elem|
535
+ if (r_elem.name == 't')
536
+ shared_table_entry << r_elem.content
548
537
  end
549
538
  end
550
539
  end
540
+ if (elem.name == 't')
541
+ shared_table_entry = elem.content
542
+ end
551
543
  end
544
+ @shared_table << shared_table_entry
552
545
  end
553
546
  end
554
547
 
@@ -556,28 +549,40 @@ class Excelx < GenericSpreadsheet
556
549
  def read_styles(doc)
557
550
  @numFmts = []
558
551
  @cellXfs = []
559
- doc.each_element do |e1|
560
- if e1.name == "styleSheet"
561
- e1.each_element do |e2|
562
- if e2.name == "numFmts"
563
- e2.each_element do |e3|
564
- if e3.name == 'numFmt'
565
- numFmtId = e3.attributes['numFmtId']
566
- formatCode = e3.attributes['formatCode']
567
- @numFmts << [numFmtId, formatCode]
568
- end
569
- end
570
- elsif e2.name == "cellXfs"
571
- e2.each_element do |e3|
572
- if e3.name == 'xf'
573
- numFmtId = e3.attributes['numFmtId']
574
- @cellXfs << [numFmtId]
552
+ fonts = []
553
+
554
+ doc.find("//*[local-name()='numFmt']").each do |numFmt|
555
+ numFmtId = numFmt.attributes.to_h['numFmtId']
556
+ formatCode = numFmt.attributes.to_h['formatCode']
557
+ @numFmts << [numFmtId, formatCode]
558
+ end
559
+ doc.find("//*[local-name()='fonts']").each do |fonts_el|
560
+ fonts_el.each_element do |font_el|
561
+ if font_el.name == 'font'
562
+ font = Excelx::Font.new
563
+ font_el.each_element do |font_sub_el|
564
+ case font_sub_el.name
565
+ when 'b'
566
+ font.bold = true
567
+ when 'i'
568
+ font.italic = true
569
+ when 'u'
570
+ font.underline = true
575
571
  end
576
- end
577
572
  end
573
+ fonts << font
578
574
  end
579
575
  end
580
576
  end
577
+
578
+ doc.find("//*[local-name()='cellXfs']").each do |xfs|
579
+ xfs.each do |xf|
580
+ numFmtId = xf.attributes.to_h['numFmtId']
581
+ @cellXfs << [numFmtId]
582
+ fontId = xf.attributes.to_h['fontId'].to_i
583
+ @style_definitions << fonts[fontId]
584
+ end
585
+ end
581
586
  end
582
587
 
583
588
  # convert internal excelx attribute to a format