hmcgowan-roo 1.2.4

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