donibuchanan-roo 1.3.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/History.txt +225 -0
  2. data/README.markdown +55 -0
  3. data/examples/roo_soap_client.rb +53 -0
  4. data/examples/roo_soap_server.rb +29 -0
  5. data/examples/write_me.rb +33 -0
  6. data/lib/roo/excel.rb +468 -0
  7. data/lib/roo/excel2003xml.rb +411 -0
  8. data/lib/roo/excelx.rb +602 -0
  9. data/lib/roo/generic_spreadsheet.rb +628 -0
  10. data/lib/roo/google.rb +379 -0
  11. data/lib/roo/openoffice.rb +451 -0
  12. data/lib/roo/roo_rails_helper.rb +82 -0
  13. data/lib/roo/version.rb +9 -0
  14. data/lib/roo.rb +32 -0
  15. data/test/1900_base.xls +0 -0
  16. data/test/1904_base.xls +0 -0
  17. data/test/Bibelbund.csv +3741 -0
  18. data/test/Bibelbund.ods +0 -0
  19. data/test/Bibelbund.xls +0 -0
  20. data/test/Bibelbund.xlsx +0 -0
  21. data/test/Bibelbund1.ods +0 -0
  22. data/test/bad_excel_date.xls +0 -0
  23. data/test/bbu.ods +0 -0
  24. data/test/bbu.xls +0 -0
  25. data/test/bbu.xlsx +0 -0
  26. data/test/bode-v1.ods.zip +0 -0
  27. data/test/bode-v1.xls.zip +0 -0
  28. data/test/boolean.ods +0 -0
  29. data/test/boolean.xls +0 -0
  30. data/test/boolean.xlsx +0 -0
  31. data/test/borders.ods +0 -0
  32. data/test/borders.xls +0 -0
  33. data/test/borders.xlsx +0 -0
  34. data/test/bug-row-column-fixnum-float.xls +0 -0
  35. data/test/datetime.ods +0 -0
  36. data/test/datetime.xls +0 -0
  37. data/test/datetime.xlsx +0 -0
  38. data/test/datetime_floatconv.xls +0 -0
  39. data/test/emptysheets.ods +0 -0
  40. data/test/emptysheets.xls +0 -0
  41. data/test/excel2003.xml +21140 -0
  42. data/test/false_encoding.xls +0 -0
  43. data/test/formula.ods +0 -0
  44. data/test/formula.xls +0 -0
  45. data/test/formula.xlsx +0 -0
  46. data/test/formula_parse_error.xls +0 -0
  47. data/test/html-escape.ods +0 -0
  48. data/test/no_spreadsheet_file.txt +1 -0
  49. data/test/numbers1.csv +18 -0
  50. data/test/numbers1.ods +0 -0
  51. data/test/numbers1.xls +0 -0
  52. data/test/numbers1.xlsx +0 -0
  53. data/test/only_one_sheet.ods +0 -0
  54. data/test/only_one_sheet.xls +0 -0
  55. data/test/only_one_sheet.xlsx +0 -0
  56. data/test/paragraph.ods +0 -0
  57. data/test/paragraph.xls +0 -0
  58. data/test/paragraph.xlsx +0 -0
  59. data/test/ric.ods +0 -0
  60. data/test/simple_spreadsheet.ods +0 -0
  61. data/test/simple_spreadsheet.xls +0 -0
  62. data/test/simple_spreadsheet.xlsx +0 -0
  63. data/test/simple_spreadsheet_from_italo.ods +0 -0
  64. data/test/simple_spreadsheet_from_italo.xls +0 -0
  65. data/test/skipped_tests.rb +789 -0
  66. data/test/style.ods +0 -0
  67. data/test/style.xls +0 -0
  68. data/test/style.xlsx +0 -0
  69. data/test/test_helper.rb +19 -0
  70. data/test/test_roo.rb +1834 -0
  71. data/test/time-test.csv +2 -0
  72. data/test/time-test.ods +0 -0
  73. data/test/time-test.xls +0 -0
  74. data/test/time-test.xlsx +0 -0
  75. data/test/whitespace.ods +0 -0
  76. data/test/whitespace.xls +0 -0
  77. data/test/whitespace.xlsx +0 -0
  78. metadata +185 -0
data/lib/roo/excelx.rb ADDED
@@ -0,0 +1,602 @@
1
+ require 'xml'
2
+ require 'fileutils'
3
+ require 'zip/zipfilesystem'
4
+ require 'date'
5
+
6
+ class String
7
+ def end_with?(str)
8
+ self[-str.length,str.length] == str
9
+ end
10
+ end
11
+
12
+ class Excelx < GenericSpreadsheet
13
+ FORMATS = {
14
+ 'General' => :float,
15
+ '0' => :float,
16
+ '0.00' => :float,
17
+ '#,##0' => :float,
18
+ '#,##0.00' => :float,
19
+ '0%' => :percentage,
20
+ '0.00%' => :percentage,
21
+ '0.00E+00' => :float,
22
+ '# ?/?' => :float, #??? TODO:
23
+ '# ??/??' => :float, #??? TODO:
24
+ 'mm-dd-yy' => :date,
25
+ 'd-mmm-yy' => :date,
26
+ 'd-mmm' => :date,
27
+ 'mmm-yy' => :date,
28
+ 'h:mm AM/PM' => :date,
29
+ 'h:mm:ss AM/PM' => :date,
30
+ 'h:mm' => :time,
31
+ 'h:mm:ss' => :time,
32
+ 'm/d/yy h:mm' => :date,
33
+ '#,##0 ;(#,##0)' => :float,
34
+ '#,##0 ;[Red](#,##0)' => :float,
35
+ '#,##0.00;(#,##0.00)' => :float,
36
+ '#,##0.00;[Red](#,##0.00)' => :float,
37
+ 'mm:ss' => :time,
38
+ '[h]:mm:ss' => :time,
39
+ 'mmss.0' => :time,
40
+ '##0.0E+0' => :float,
41
+ '@' => :float,
42
+ #-- zusaetzliche Formate, die nicht standardmaessig definiert sind:
43
+ "yyyy\\-mm\\-dd" => :date,
44
+ 'dd/mm/yy' => :date,
45
+ 'hh:mm:ss' => :time,
46
+ "dd/mm/yy\\ hh:mm" => :datetime,
47
+ }
48
+ STANDARD_FORMATS = {
49
+ 0 => 'General',
50
+ 1 => '0',
51
+ 2 => '0.00',
52
+ 3 => '#,##0',
53
+ 4 => '#,##0.00',
54
+ 9 => '0%',
55
+ 10 => '0.00%',
56
+ 11 => '0.00E+00',
57
+ 12 => '# ?/?',
58
+ 13 => '# ??/??',
59
+ 14 => 'mm-dd-yy',
60
+ 15 => 'd-mmm-yy',
61
+ 16 => 'd-mmm',
62
+ 17 => 'mmm-yy',
63
+ 18 => 'h:mm AM/PM',
64
+ 19 => 'h:mm:ss AM/PM',
65
+ 20 => 'h:mm',
66
+ 21 => 'h:mm:ss',
67
+ 22 => 'm/d/yy h:mm',
68
+ 37 => '#,##0 ;(#,##0)',
69
+ 38 => '#,##0 ;[Red](#,##0)',
70
+ 39 => '#,##0.00;(#,##0.00)',
71
+ 40 => '#,##0.00;[Red](#,##0.00)',
72
+ 45 => 'mm:ss',
73
+ 46 => '[h]:mm:ss',
74
+ 47 => 'mmss.0',
75
+ 48 => '##0.0E+0',
76
+ 49 => '@',
77
+ }
78
+ @@nr = 0
79
+
80
+ # initialization and opening of a spreadsheet file
81
+ # values for packed: :zip
82
+ def initialize(filename, packed=nil, file_warning = :error) #, create = false)
83
+ super()
84
+ @file_warning = file_warning
85
+ @tmpdir = "oo_"+$$.to_s
86
+ @tmpdir = File.join(ENV['ROO_TMP'], @tmpdir) if ENV['ROO_TMP']
87
+ unless File.exists?(@tmpdir)
88
+ FileUtils::mkdir(@tmpdir)
89
+ end
90
+ filename = open_from_uri(filename) if filename[0,7] == "http://"
91
+ filename = unzip(filename) if packed and packed == :zip
92
+ begin
93
+ file_type_check(filename,'.xlsx','an Excel-xlsx')
94
+ @cells_read = Hash.new
95
+ @filename = filename
96
+ unless File.file?(@filename)
97
+ raise IOError, "file #{@filename} does not exist"
98
+ end
99
+ @@nr += 1
100
+ @file_nr = @@nr
101
+ extract_content(@filename)
102
+ file = File.new(File.join(@tmpdir, @file_nr.to_s+"_roo_workbook.xml"))
103
+ @workbook_doc = XML::Parser.io(file).parse
104
+ file.close
105
+ @shared_table = []
106
+ if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml'))
107
+ file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml'))
108
+ @sharedstring_doc = XML::Parser.io(file).parse
109
+ file.close
110
+ read_shared_strings(@sharedstring_doc)
111
+ end
112
+ @styles_table = []
113
+ @style_definitions = Array.new { |h,k| h[k] = {} }
114
+ if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
115
+ file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
116
+ @styles_doc = XML::Parser.io(file).parse
117
+ file.close
118
+ read_styles(@styles_doc)
119
+ end
120
+ @sheet_doc = []
121
+ @sheet_files.each_with_index do |item, i|
122
+ file = File.new(item)
123
+ @sheet_doc[i] = XML::Parser.io(file).parse
124
+ file.close
125
+ end
126
+ ensure
127
+ #if ENV["roo_local"] != "thomas-p"
128
+ FileUtils::rm_r(@tmpdir)
129
+ #end
130
+ end
131
+ @default_sheet = self.sheets.first
132
+ @cell = Hash.new
133
+ @cell_type = Hash.new
134
+ @formula = Hash.new
135
+ @first_row = Hash.new
136
+ @last_row = Hash.new
137
+ @first_column = Hash.new
138
+ @last_column = Hash.new
139
+ @header_line = 1
140
+ @excelx_type = Hash.new
141
+ @excelx_value = Hash.new
142
+ @s_attribute = Hash.new # TODO: ggf. wieder entfernen nur lokal benoetigt
143
+ end
144
+
145
+ # Returns the content of a spreadsheet-cell.
146
+ # (1,1) is the upper left corner.
147
+ # (1,1), (1,'A'), ('A',1), ('a',1) all refers to the
148
+ # cell at the first line and first row.
149
+ def cell(row, col, sheet=nil)
150
+ sheet = @default_sheet unless sheet
151
+ read_cells(sheet) unless @cells_read[sheet]
152
+ row,col = normalize(row,col)
153
+ if celltype(row,col,sheet) == :date
154
+ yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
155
+ return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
156
+ elsif celltype(row,col,sheet) == :datetime
157
+ date_part,time_part = @cell[sheet][[row,col]].split(' ')
158
+ yyyy,mm,dd = date_part.split('-')
159
+ hh,mi,ss = time_part.split(':')
160
+ return DateTime.civil(yyyy.to_i,mm.to_i,dd.to_i,hh.to_i,mi.to_i,ss.to_i)
161
+ end
162
+ @cell[sheet][[row,col]]
163
+ end
164
+
165
+ # Returns the formula at (row,col).
166
+ # Returns nil if there is no formula.
167
+ # The method #formula? checks if there is a formula.
168
+ def formula(row,col,sheet=nil)
169
+ sheet = @default_sheet unless sheet
170
+ read_cells(sheet) unless @cells_read[sheet]
171
+ row,col = normalize(row,col)
172
+ if @formula[sheet][[row,col]] == nil
173
+ return nil
174
+ else
175
+ return @formula[sheet][[row,col]]
176
+ end
177
+ end
178
+
179
+ # true, if there is a formula
180
+ def formula?(row,col,sheet=nil)
181
+ sheet = @default_sheet unless sheet
182
+ read_cells(sheet) unless @cells_read[sheet]
183
+ row,col = normalize(row,col)
184
+ formula(row,col) != nil
185
+ end
186
+
187
+ class Font
188
+ attr_accessor :bold, :italic, :underline
189
+
190
+ def bold?
191
+ @bold == true
192
+ end
193
+
194
+ def italic?
195
+ @italic == true
196
+ end
197
+
198
+ def underline?
199
+ @underline == true
200
+ end
201
+ end
202
+
203
+ # Given a cell, return the cell's style
204
+ def font(row, col, sheet=nil)
205
+ sheet = @default_sheet unless sheet
206
+ read_cells(sheet) unless @cells_read[sheet]
207
+ row,col = normalize(row,col)
208
+ s_attribute = @s_attribute[sheet][[row,col]]
209
+ s_attribute ||= 0
210
+ s_attribute = s_attribute.to_i
211
+ @style_definitions[s_attribute]
212
+ end
213
+
214
+ # set a cell to a certain value
215
+ # (this will not be saved back to the spreadsheet file!)
216
+ def set(row,col,value,sheet=nil) #:nodoc:
217
+ sheet = @default_sheet unless sheet
218
+ read_cells(sheet) unless @cells_read[sheet]
219
+ row,col = normalize(row,col)
220
+ set_value(row,col,value,sheet)
221
+ if value.class == Fixnum
222
+ set_type(row,col,:float,sheet)
223
+ elsif value.class == String
224
+ set_type(row,col,:string,sheet)
225
+ elsif value.class == Float
226
+ set_type(row,col,:string,sheet)
227
+ else
228
+ raise ArgumentError, "Type for "+value.to_s+" not set"
229
+ end
230
+ end
231
+
232
+ # returns the type of a cell:
233
+ # * :float
234
+ # * :string,
235
+ # * :date
236
+ # * :percentage
237
+ # * :formula
238
+ # * :time
239
+ # * :datetime
240
+ def celltype(row,col,sheet=nil)
241
+ sheet = @default_sheet unless sheet
242
+ read_cells(sheet) unless @cells_read[sheet]
243
+ row,col = normalize(row,col)
244
+ if @formula[sheet][[row,col]]
245
+ return :formula
246
+ else
247
+ @cell_type[sheet][[row,col]]
248
+ end
249
+ end
250
+
251
+ # returns the internal type of an excel cell
252
+ # * :numeric_or_formula
253
+ # * :string
254
+ # Note: this is only available within the Excelx class
255
+ def excelx_type(row,col,sheet=nil)
256
+ sheet = @default_sheet unless sheet
257
+ read_cells(sheet) unless @cells_read[sheet]
258
+ row,col = normalize(row,col)
259
+ return @excelx_type[sheet][[row,col]]
260
+ end
261
+
262
+ # returns the internal value of an excelx cell
263
+ # Note: this is only available within the Excelx class
264
+ def excelx_value(row,col,sheet=nil)
265
+ sheet = @default_sheet unless sheet
266
+ read_cells(sheet) unless @cells_read[sheet]
267
+ row,col = normalize(row,col)
268
+ return @excelx_value[sheet][[row,col]]
269
+ end
270
+
271
+ # returns the internal format of an excel cell
272
+ def excelx_format(row,col,sheet=nil)
273
+ sheet = @default_sheet unless sheet
274
+ read_cells(sheet) unless @cells_read[sheet]
275
+ row,col = normalize(row,col)
276
+ s = @s_attribute[sheet][[row,col]]
277
+ result = attribute2format(s)
278
+ result
279
+ end
280
+
281
+ # returns an array of sheet names in the spreadsheet
282
+ def sheets
283
+ return_sheets = []
284
+ @workbook_doc.find("//*[local-name()='sheet']").each do |sheet|
285
+ return_sheets << sheet.attributes.to_h['name']
286
+ end
287
+ return_sheets
288
+ end
289
+ # shows the internal representation of all cells
290
+ # for debugging purposes
291
+ def to_s(sheet=nil)
292
+ sheet = @default_sheet unless sheet
293
+ read_cells(sheet) unless @cells_read[sheet]
294
+ @cell[sheet].inspect
295
+ end
296
+
297
+ # returns each formula in the selected sheet as an array of elements
298
+ # [row, col, formula]
299
+ def formulas(sheet=nil)
300
+ theformulas = Array.new
301
+ sheet = @default_sheet unless sheet
302
+ read_cells(sheet) unless @cells_read[sheet]
303
+ first_row(sheet).upto(last_row(sheet)) {|row|
304
+ first_column(sheet).upto(last_column(sheet)) {|col|
305
+ if formula?(row,col,sheet)
306
+ f = [row, col, formula(row,col,sheet)]
307
+ theformulas << f
308
+ end
309
+ }
310
+ }
311
+ theformulas
312
+ end
313
+
314
+ private
315
+
316
+ # helper function to set the internal representation of cells
317
+ def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v,
318
+ excelx_type=nil,
319
+ excelx_value=nil,
320
+ s_attribute=nil)
321
+ key = [y,x+i]
322
+ @cell_type[sheet] = {} unless @cell_type[sheet]
323
+ @cell_type[sheet][key] = vt
324
+ @formula[sheet] = {} unless @formula[sheet]
325
+ @formula[sheet][key] = formula if formula
326
+ @cell[sheet] = {} unless @cell[sheet]
327
+ case @cell_type[sheet][key]
328
+ when :float
329
+ @cell[sheet][key] = v.to_f
330
+ when :string
331
+ @cell[sheet][key] = str_v
332
+ when :date
333
+ @cell[sheet][key] = (Date.new(1899,12,30)+v.to_i).strftime("%Y-%m-%d")
334
+ when :datetime
335
+ @cell[sheet][key] = (DateTime.new(1899,12,30)+v.to_f).strftime("%Y-%m-%d %H:%M:%S")
336
+ when :percentage
337
+ @cell[sheet][key] = v.to_f
338
+ when :time
339
+ @cell[sheet][key] = v.to_f*(24*60*60)
340
+ else
341
+ @cell[sheet][key] = v
342
+ end
343
+ @excelx_type[sheet] = {} unless @excelx_type[sheet]
344
+ @excelx_type[sheet][key] = excelx_type
345
+ @excelx_value[sheet] = {} unless @excelx_value[sheet]
346
+ @excelx_value[sheet][key] = excelx_value
347
+ @s_attribute[sheet] = {} unless @s_attribute[sheet]
348
+ @s_attribute[sheet][key] = s_attribute
349
+ end
350
+
351
+ # splits a coordinate like "AA12" into the parts "AA" (String) and 12 (Fixnum)
352
+ def split_coord(s)
353
+ letter = ""
354
+ number = 0
355
+ i = 0
356
+ while i<s.length and "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".include?(s[i,1])
357
+ letter += s[i,1]
358
+ i+=1
359
+ end
360
+ while i<s.length and "0123456789".include?(s[i,1])
361
+ number = number*10 + s[i,1].to_i
362
+ i+=1
363
+ end
364
+ if letter=="" or number==0
365
+ raise ArgumentError
366
+ end
367
+ return letter,number
368
+ end
369
+
370
+ def split_coordinate(str)
371
+ letter,number = split_coord(str)
372
+ x = GenericSpreadsheet.letter_to_number(letter)
373
+ y = number
374
+ return x,y
375
+ end
376
+
377
+ # read all cells in the selected sheet
378
+ def format2type(format)
379
+ if FORMATS.has_key? format
380
+ FORMATS[format]
381
+ else
382
+ :float
383
+ end
384
+ end
385
+
386
+ # read all cells in the selected sheet
387
+ def read_cells(sheet=nil)
388
+ sheet = @default_sheet unless sheet
389
+ sheet_found = false
390
+ raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
391
+ raise RangeError unless self.sheets.include? sheet
392
+ n = self.sheets.index(sheet)
393
+ @sheet_doc[n].find("//*[local-name()='c']").each do |c|
394
+ s_attribute = c.attributes.to_h['s'].to_i # should be here
395
+ if (c.attributes.to_h['t'] == 's')
396
+ tmp_type = :shared
397
+ elsif (c.attributes.to_h['t'] == 'b')
398
+ tmp_type = :boolean
399
+ else
400
+ # s_attribute = c.attributes.to_h['s'].to_i # was here
401
+ format = attribute2format(s_attribute)
402
+ tmp_type = format2type(format)
403
+ end
404
+ formula = nil
405
+ c.each_element do |cell|
406
+ if cell.name == 'f'
407
+ formula = cell.content
408
+ end
409
+ if cell.name == 'v'
410
+ if tmp_type == :time or tmp_type == :datetime
411
+ if cell.content.to_f >= 1.0
412
+ if (cell.content.to_f - cell.content.to_f.floor).abs > 0.000001
413
+ tmp_type = :datetime
414
+ else
415
+ tmp_type = :date
416
+ end
417
+ else
418
+ end
419
+ end
420
+ excelx_type = [:numeric_or_formula,format]
421
+ excelx_value = cell.content
422
+ if tmp_type == :shared
423
+ vt = :string
424
+ str_v = @shared_table[cell.content.to_i]
425
+ excelx_type = :string
426
+ elsif tmp_type == :boolean
427
+ vt = :boolean
428
+ cell.content.to_i == 1 ? v = 'TRUE' : v = 'FALSE'
429
+ elsif tmp_type == :date
430
+ vt = :date
431
+ v = cell.content
432
+ elsif tmp_type == :time
433
+ vt = :time
434
+ v = cell.content
435
+ elsif tmp_type == :datetime
436
+ vt = :datetime
437
+ v = cell.content
438
+ elsif tmp_type == :formula
439
+ vt = :formula
440
+ v = cell.content.to_f #TODO: !!!!
441
+ else
442
+ vt = :float
443
+ v = cell.content
444
+ end
445
+ #puts "vt: #{vt}" if cell.text.include? "22606.5120"
446
+ x,y = split_coordinate(c.attributes.to_h['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
452
+ sheet_found = true #TODO:
453
+ if !sheet_found
454
+ raise RangeError
455
+ end
456
+ @cells_read[sheet] = true
457
+ end
458
+
459
+ # Checks if the default_sheet exists. If not an RangeError exception is
460
+ # raised
461
+ def check_default_sheet
462
+ sheet_found = false
463
+ raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil
464
+
465
+ sheet_found = true if sheets.include?(@default_sheet)
466
+
467
+ if ! sheet_found
468
+ raise RangeError, "sheet '#{@default_sheet}' not found"
469
+ end
470
+ end
471
+
472
+ # extracts all needed files from the zip file
473
+ def process_zipfile(zipfilename, zip, path='')
474
+ @sheet_files = []
475
+ Zip::ZipFile.open(zipfilename) {|zf|
476
+ zf.entries.each {|entry|
477
+ #entry.extract
478
+ if entry.to_s.end_with?('workbook.xml')
479
+ open(@tmpdir+'/'+@file_nr.to_s+'_roo_workbook.xml','wb') {|f|
480
+ f << zip.read(entry)
481
+ }
482
+ end
483
+ if entry.to_s.end_with?('sharedStrings.xml')
484
+ open(@tmpdir+'/'+@file_nr.to_s+'_roo_sharedStrings.xml','wb') {|f|
485
+ f << zip.read(entry)
486
+ }
487
+ end
488
+ if entry.to_s.end_with?('styles.xml')
489
+ open(@tmpdir+'/'+@file_nr.to_s+'_roo_styles.xml','wb') {|f|
490
+ f << zip.read(entry)
491
+ }
492
+ end
493
+ if entry.to_s =~ /sheet([0-9]+).xml$/
494
+ nr = $1
495
+ open(@tmpdir+'/'+@file_nr.to_s+"_roo_sheet#{nr}",'wb') {|f|
496
+ f << zip.read(entry)
497
+ }
498
+ @sheet_files[nr.to_i-1] = @tmpdir+'/'+@file_nr.to_s+"_roo_sheet#{nr}"
499
+ end
500
+ }
501
+ }
502
+ return
503
+ end
504
+
505
+ # extract files from the zip file
506
+ def extract_content(zipfilename)
507
+ Zip::ZipFile.open(@filename) do |zip|
508
+ process_zipfile(zipfilename,zip)
509
+ end
510
+ end
511
+
512
+ # sets the value of a cell
513
+ def set_value(row,col,value,sheet=nil)
514
+ sheet = @default_value unless sheet
515
+ @cell[sheet][[row,col]] = value
516
+ end
517
+
518
+ # sets the type of a cell
519
+ def set_type(row,col,type,sheet=nil)
520
+ sheet = @default_value unless sheet
521
+ @cell_type[sheet][[row,col]] = type
522
+ end
523
+
524
+ # read the shared strings xml document
525
+ def read_shared_strings(doc)
526
+ doc.find("//*[local-name()='si']").each do |si|
527
+ shared_table_entry = ''
528
+ si.each_element do |elem|
529
+ if (elem.name == 'r')
530
+ elem.each_element do |r_elem|
531
+ if (r_elem.name == 't')
532
+ shared_table_entry << r_elem.content
533
+ end
534
+ end
535
+ end
536
+ if (elem.name == 't')
537
+ shared_table_entry = elem.content
538
+ end
539
+ end
540
+ @shared_table << shared_table_entry
541
+ end
542
+ end
543
+
544
+ # read the styles elements of an excelx document
545
+ def read_styles(doc)
546
+ @numFmts = []
547
+ @cellXfs = []
548
+ fonts = []
549
+
550
+ doc.find("//*[local-name()='numFmt']").each do |numFmt|
551
+ numFmtId = numFmt.attributes.to_h['numFmtId']
552
+ formatCode = numFmt.attributes.to_h['formatCode']
553
+ @numFmts << [numFmtId, formatCode]
554
+ end
555
+ doc.find("//*[local-name()='fonts']").each do |fonts_el|
556
+ fonts_el.each_element do |font_el|
557
+ if font_el.name == 'font'
558
+ font = Excelx::Font.new
559
+ font_el.each_element do |font_sub_el|
560
+ case font_sub_el.name
561
+ when 'b'
562
+ font.bold = true
563
+ when 'i'
564
+ font.italic = true
565
+ when 'u'
566
+ font.underline = true
567
+ end
568
+ end
569
+ fonts << font
570
+ end
571
+ end
572
+ end
573
+
574
+ doc.find("//*[local-name()='cellXfs']").each do |xfs|
575
+ xfs.each do |xf|
576
+ numFmtId = xf.attributes.to_h['numFmtId']
577
+ @cellXfs << [numFmtId]
578
+ fontId = xf.attributes.to_h['fontId'].to_i
579
+ @style_definitions << fonts[fontId]
580
+ end
581
+ end
582
+ end
583
+
584
+ # convert internal excelx attribute to a format
585
+ def attribute2format(s)
586
+ result = nil
587
+ @numFmts.each {|nf|
588
+ if nf.first == @cellXfs[s.to_i].first
589
+ result = nf[1]
590
+ break
591
+ end
592
+ }
593
+ unless result
594
+ id = @cellXfs[s.to_i].first.to_i
595
+ if STANDARD_FORMATS.has_key? id
596
+ result = STANDARD_FORMATS[id]
597
+ end
598
+ end
599
+ result
600
+ end
601
+
602
+ end # class