hmcgowan-roo 1.2.4

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