roo 1.10.1 → 1.10.2

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 (136) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +38 -0
  4. data/History.txt +4 -4
  5. data/License.txt +20 -0
  6. data/Manifest.txt +68 -0
  7. data/README.markdown +109 -0
  8. data/Rakefile +5 -4
  9. data/bin/roo +0 -0
  10. data/examples/roo_soap_client.rb +53 -0
  11. data/examples/roo_soap_server.rb +29 -0
  12. data/examples/write_me.rb +33 -0
  13. data/lib/roo.rb +20 -61
  14. data/lib/roo/csv.rb +13 -11
  15. data/lib/roo/excel.rb +108 -219
  16. data/lib/roo/excel2003xml.rb +312 -0
  17. data/lib/roo/excelx.rb +205 -341
  18. data/lib/roo/generic_spreadsheet.rb +371 -268
  19. data/lib/roo/google.rb +64 -54
  20. data/lib/roo/openoffice.rb +101 -156
  21. data/lib/roo/roo_rails_helper.rb +5 -5
  22. data/lib/roo/worksheet.rb +18 -0
  23. data/roo.gemspec +43 -0
  24. data/scripts/txt2html +67 -0
  25. data/test/all_ss.rb +8 -10
  26. data/test/{1900_base.xls → files/1900_base.xls} +0 -0
  27. data/test/{1904_base.xls → files/1904_base.xls} +0 -0
  28. data/test/{Bibelbund.csv → files/Bibelbund.csv} +0 -0
  29. data/test/{Bibelbund.ods → files/Bibelbund.ods} +0 -0
  30. data/test/{Bibelbund.xls → files/Bibelbund.xls} +0 -0
  31. data/test/{Bibelbund.xlsx → files/Bibelbund.xlsx} +0 -0
  32. data/test/files/Bibelbund.xml +62518 -0
  33. data/test/{Bibelbund1.ods → files/Bibelbund1.ods} +0 -0
  34. data/test/{Pfand_from_windows_phone.xlsx → files/Pfand_from_windows_phone.xlsx} +0 -0
  35. data/test/files/bad_excel_date.xls +0 -0
  36. data/test/{bbu.ods → files/bbu.ods} +0 -0
  37. data/test/{bbu.xls → files/bbu.xls} +0 -0
  38. data/test/{bbu.xlsx → files/bbu.xlsx} +0 -0
  39. data/test/files/bbu.xml +152 -0
  40. data/test/{bode-v1.ods.zip → files/bode-v1.ods.zip} +0 -0
  41. data/test/{bode-v1.xls.zip → files/bode-v1.xls.zip} +0 -0
  42. data/test/{boolean.ods → files/boolean.ods} +0 -0
  43. data/test/{boolean.xls → files/boolean.xls} +0 -0
  44. data/test/{boolean.xlsx → files/boolean.xlsx} +0 -0
  45. data/test/files/boolean.xml +112 -0
  46. data/test/{borders.ods → files/borders.ods} +0 -0
  47. data/test/{borders.xls → files/borders.xls} +0 -0
  48. data/test/{borders.xlsx → files/borders.xlsx} +0 -0
  49. data/test/files/borders.xml +144 -0
  50. data/test/{bug-row-column-fixnum-float.xls → files/bug-row-column-fixnum-float.xls} +0 -0
  51. data/test/files/bug-row-column-fixnum-float.xml +127 -0
  52. data/test/{comments.ods → files/comments.ods} +0 -0
  53. data/test/{comments.xls → files/comments.xls} +0 -0
  54. data/test/{comments.xlsx → files/comments.xlsx} +0 -0
  55. data/test/{csvtypes.csv → files/csvtypes.csv} +0 -0
  56. data/test/{datetime.ods → files/datetime.ods} +0 -0
  57. data/test/{datetime.xls → files/datetime.xls} +0 -0
  58. data/test/{datetime.xlsx → files/datetime.xlsx} +0 -0
  59. data/test/files/datetime.xml +142 -0
  60. data/test/{datetime_floatconv.xls → files/datetime_floatconv.xls} +0 -0
  61. data/test/files/datetime_floatconv.xml +148 -0
  62. data/test/{dreimalvier.ods → files/dreimalvier.ods} +0 -0
  63. data/test/{emptysheets.ods → files/emptysheets.ods} +0 -0
  64. data/test/{emptysheets.xls → files/emptysheets.xls} +0 -0
  65. data/test/{emptysheets.xlsx → files/emptysheets.xlsx} +0 -0
  66. data/test/files/emptysheets.xml +105 -0
  67. data/test/files/excel2003.xml +21140 -0
  68. data/test/{false_encoding.xls → files/false_encoding.xls} +0 -0
  69. data/test/files/false_encoding.xml +132 -0
  70. data/test/{formula.ods → files/formula.ods} +0 -0
  71. data/test/{formula.xls → files/formula.xls} +0 -0
  72. data/test/{formula.xlsx → files/formula.xlsx} +0 -0
  73. data/test/files/formula.xml +134 -0
  74. data/test/files/formula_parse_error.xls +0 -0
  75. data/test/files/formula_parse_error.xml +1833 -0
  76. data/test/{formula_string_error.xlsx → files/formula_string_error.xlsx} +0 -0
  77. data/test/{html-escape.ods → files/html-escape.ods} +0 -0
  78. data/test/{matrix.ods → files/matrix.ods} +0 -0
  79. data/test/{matrix.xls → files/matrix.xls} +0 -0
  80. data/test/{named_cells.ods → files/named_cells.ods} +0 -0
  81. data/test/{named_cells.xls → files/named_cells.xls} +0 -0
  82. data/test/{named_cells.xlsx → files/named_cells.xlsx} +0 -0
  83. data/test/{no_spreadsheet_file.txt → files/no_spreadsheet_file.txt} +0 -0
  84. data/test/{numbers1.csv → files/numbers1.csv} +0 -0
  85. data/test/{numbers1.ods → files/numbers1.ods} +0 -0
  86. data/test/{numbers1.xls → files/numbers1.xls} +0 -0
  87. data/test/{numbers1.xlsx → files/numbers1.xlsx} +0 -0
  88. data/test/files/numbers1.xml +312 -0
  89. data/test/{only_one_sheet.ods → files/only_one_sheet.ods} +0 -0
  90. data/test/{only_one_sheet.xls → files/only_one_sheet.xls} +0 -0
  91. data/test/{only_one_sheet.xlsx → files/only_one_sheet.xlsx} +0 -0
  92. data/test/files/only_one_sheet.xml +67 -0
  93. data/test/{paragraph.ods → files/paragraph.ods} +0 -0
  94. data/test/{paragraph.xls → files/paragraph.xls} +0 -0
  95. data/test/{paragraph.xlsx → files/paragraph.xlsx} +0 -0
  96. data/test/files/paragraph.xml +127 -0
  97. data/test/{prova.xls → files/prova.xls} +0 -0
  98. data/test/{ric.ods → files/ric.ods} +0 -0
  99. data/test/{simple_spreadsheet.ods → files/simple_spreadsheet.ods} +0 -0
  100. data/test/{simple_spreadsheet.xls → files/simple_spreadsheet.xls} +0 -0
  101. data/test/{simple_spreadsheet.xlsx → files/simple_spreadsheet.xlsx} +0 -0
  102. data/test/files/simple_spreadsheet.xml +225 -0
  103. data/test/{simple_spreadsheet_from_italo.ods → files/simple_spreadsheet_from_italo.ods} +0 -0
  104. data/test/{simple_spreadsheet_from_italo.xls → files/simple_spreadsheet_from_italo.xls} +0 -0
  105. data/test/files/simple_spreadsheet_from_italo.xml +242 -0
  106. data/test/{so_datetime.csv → files/so_datetime.csv} +0 -0
  107. data/test/{style.ods → files/style.ods} +0 -0
  108. data/test/{style.xls → files/style.xls} +0 -0
  109. data/test/{style.xlsx → files/style.xlsx} +0 -0
  110. data/test/files/style.xml +154 -0
  111. data/test/{time-test.csv → files/time-test.csv} +0 -0
  112. data/test/{time-test.ods → files/time-test.ods} +0 -0
  113. data/test/{time-test.xls → files/time-test.xls} +0 -0
  114. data/test/{time-test.xlsx → files/time-test.xlsx} +0 -0
  115. data/test/files/time-test.xml +131 -0
  116. data/test/{type_excel.ods → files/type_excel.ods} +0 -0
  117. data/test/{type_excel.xlsx → files/type_excel.xlsx} +0 -0
  118. data/test/{type_excelx.ods → files/type_excelx.ods} +0 -0
  119. data/test/{type_excelx.xls → files/type_excelx.xls} +0 -0
  120. data/test/{type_openoffice.xls → files/type_openoffice.xls} +0 -0
  121. data/test/{type_openoffice.xlsx → files/type_openoffice.xlsx} +0 -0
  122. data/test/{whitespace.ods → files/whitespace.ods} +0 -0
  123. data/test/{whitespace.xls → files/whitespace.xls} +0 -0
  124. data/test/{whitespace.xlsx → files/whitespace.xlsx} +0 -0
  125. data/test/files/whitespace.xml +184 -0
  126. data/test/test_generic_spreadsheet.rb +257 -0
  127. data/test/test_helper.rb +167 -27
  128. data/test/test_roo.rb +1178 -930
  129. data/website/index.html +385 -0
  130. data/website/index.txt +423 -0
  131. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  132. data/website/stylesheets/screen.css +130 -0
  133. data/website/template.rhtml +48 -0
  134. metadata +151 -121
  135. data/README.txt +0 -110
  136. data/lib/roo/.csv.rb.swp +0 -0
@@ -0,0 +1,312 @@
1
+ require 'fileutils'
2
+ require 'zip/zipfilesystem'
3
+ require 'date'
4
+ require 'base64'
5
+ require 'cgi'
6
+
7
+ class Roo::Excel2003XML < Roo::GenericSpreadsheet
8
+
9
+ # initialization and opening of a spreadsheet file
10
+ # values for packed: :zip
11
+ def initialize(filename, packed=nil, file_warning=:error)
12
+ make_tmpdir do |tmpdir|
13
+ filename = open_from_uri(filename, tmpdir) if uri?(filename)
14
+ filename = unzip(filename, tmpdir) if packed == :zip
15
+
16
+ file_type_check(filename,'.xml','an Excel 2003 XML', file_warning)
17
+ @cells_read = Hash.new
18
+ @filename = filename
19
+ unless File.file?(@filename)
20
+ raise IOError, "file #{@filename} does not exist"
21
+ end
22
+ @doc = Nokogiri::XML(open(@filename))
23
+ end
24
+ @default_sheet = self.sheets.first
25
+ @cell = Hash.new
26
+ @cell_type = Hash.new
27
+ @formula = Hash.new
28
+ @first_row = Hash.new
29
+ @last_row = Hash.new
30
+ @first_column = Hash.new
31
+ @last_column = Hash.new
32
+ @header_line = 1
33
+ @style = Hash.new
34
+ @style_defaults = Hash.new { |h,k| h[k] = [] }
35
+ @style_definitions = Hash.new
36
+ read_styles
37
+ end
38
+
39
+ # Returns the content of a spreadsheet-cell.
40
+ # (1,1) is the upper left corner.
41
+ # (1,1), (1,'A'), ('A',1), ('a',1) all refers to the
42
+ # cell at the first line and first row.
43
+ def cell(row, col, sheet=nil)
44
+ sheet ||= @default_sheet
45
+ read_cells(sheet) unless @cells_read[sheet]
46
+ row,col = normalize(row,col)
47
+ if celltype(row,col,sheet) == :date
48
+ yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
49
+ return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
50
+ end
51
+ @cell[sheet][[row,col]]
52
+ end
53
+
54
+ # Returns the formula at (row,col).
55
+ # Returns nil if there is no formula.
56
+ # The method #formula? checks if there is a formula.
57
+ def formula(row,col,sheet=nil)
58
+ sheet ||= @default_sheet
59
+ read_cells(sheet) unless @cells_read[sheet]
60
+ row,col = normalize(row,col)
61
+ if @formula[sheet][[row,col]] == nil
62
+ return nil
63
+ else
64
+ return @formula[sheet][[row,col]]["oooc:".length..-1]
65
+ end
66
+ end
67
+
68
+ # true, if there is a formula
69
+ def formula?(row,col,sheet=nil)
70
+ sheet ||= @default_sheet
71
+ read_cells(sheet) unless @cells_read[sheet]
72
+ row,col = normalize(row,col)
73
+ formula(row,col) != nil
74
+ end
75
+
76
+ class Font
77
+ attr_accessor :bold, :italic, :underline
78
+
79
+ def bold?
80
+ @bold == '1'
81
+ end
82
+
83
+ def italic?
84
+ @italic == '1'
85
+ end
86
+
87
+ def underline?
88
+ @underline != nil
89
+ end
90
+ end
91
+
92
+ # Given a cell, return the cell's style
93
+ def font(row, col, sheet=nil)
94
+ sheet ||= @default_sheet
95
+ read_cells(sheet) unless @cells_read[sheet]
96
+ row,col = normalize(row,col)
97
+ style_name = @style[sheet][[row,col]] || @style_defaults[sheet][col - 1] || 'Default'
98
+ @style_definitions[style_name]
99
+ end
100
+
101
+ # returns the type of a cell:
102
+ # * :float
103
+ # * :string
104
+ # * :date
105
+ # * :percentage
106
+ # * :formula
107
+ # * :time
108
+ # * :datetime
109
+ def celltype(row,col,sheet=nil)
110
+ sheet ||= @default_sheet
111
+ read_cells(sheet) unless @cells_read[sheet]
112
+ row,col = normalize(row,col)
113
+ if @formula[sheet][[row,col]]
114
+ return :formula
115
+ else
116
+ @cell_type[sheet][[row,col]]
117
+ end
118
+ end
119
+
120
+ def sheets
121
+ @doc.xpath("/ss:Workbook/ss:Worksheet").map do |sheet|
122
+ sheet['Name']
123
+ end
124
+ end
125
+
126
+ # version of the openoffice document
127
+ # at 2007 this is always "1.0"
128
+ def officeversion
129
+ oo_version
130
+ @officeversion
131
+ end
132
+
133
+ # shows the internal representation of all cells
134
+ # mainly for debugging purposes
135
+ def to_s(sheet=nil)
136
+ sheet ||= @default_sheet
137
+ read_cells(sheet) unless @cells_read[sheet]
138
+ @cell[sheet].inspect
139
+ end
140
+
141
+ # save spreadsheet
142
+ def save #:nodoc:
143
+ 42
144
+ end
145
+
146
+ # returns each formula in the selected sheet as an array of elements
147
+ # [row, col, formula]
148
+ def formulas(sheet=nil)
149
+ theformulas = Array.new
150
+ sheet ||= @default_sheet
151
+ read_cells(sheet) unless @cells_read[sheet]
152
+ first_row(sheet).upto(last_row(sheet)) {|row|
153
+ first_column(sheet).upto(last_column(sheet)) {|col|
154
+ if formula?(row,col,sheet)
155
+ f = [row, col, formula(row,col,sheet)]
156
+ theformulas << f
157
+ end
158
+ }
159
+ }
160
+ theformulas
161
+ end
162
+
163
+ private
164
+
165
+ # read the version of the OO-Version
166
+ def oo_version
167
+ @doc.find("//*[local-name()='document-content']").each do |office|
168
+ @officeversion = office['version']
169
+ end
170
+ end
171
+
172
+ # helper function to set the internal representation of cells
173
+ def set_cell_values(sheet,x,y,i,v,value_type,formula,table_cell,str_v,style_name)
174
+ key = [y,x+i]
175
+ @cell_type[sheet] = {} unless @cell_type[sheet]
176
+ @cell_type[sheet][key] = value_type
177
+ @formula[sheet] = {} unless @formula[sheet]
178
+ @formula[sheet][key] = formula if formula
179
+ @cell[sheet] = {} unless @cell[sheet]
180
+ @style[sheet] = {} unless @style[sheet]
181
+ @style[sheet][key] = style_name
182
+ @cell[sheet][key] =
183
+ case @cell_type[sheet][key]
184
+ when :float
185
+ v.to_f
186
+ when :string
187
+ str_v
188
+ when :datetime
189
+ DateTime.parse(v)
190
+ when :percentage
191
+ v.to_f
192
+ # when :time
193
+ # hms = v.split(':')
194
+ # hms[0].to_i*3600 + hms[1].to_i*60 + hms[2].to_i
195
+ else
196
+ v
197
+ end
198
+ end
199
+
200
+ # read all cells in the selected sheet
201
+ #--
202
+ # the following construct means '4 blanks'
203
+ # some content <text:s text:c="3"/>
204
+ #++
205
+ def read_cells(sheet=nil)
206
+ sheet ||= @default_sheet
207
+ sheet_found = false
208
+ raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
209
+ raise RangeError unless self.sheets.include? sheet
210
+ @doc.xpath("/ss:Workbook/ss:Worksheet[@ss:Name='#{sheet}']").each do |ws|
211
+ sheet_found = true
212
+ row = 1
213
+ col = 1
214
+ column_attributes = {}
215
+ idx = 0
216
+ ws.xpath('./ss:Table/ss:Column').each do |c|
217
+ column_attributes[(idx += 1).to_s] = c['StyleID']
218
+ end
219
+ ws.xpath('./ss:Table/ss:Row').each do |r|
220
+ skip_to_row = r['Index'].to_i
221
+ row = skip_to_row if skip_to_row > 0
222
+ style_name = r['StyleID'] if r['StyleID']
223
+ r.xpath('./ss:Cell').each do |c|
224
+ skip_to_col = c['Index'].to_i
225
+ col = skip_to_col if skip_to_col > 0
226
+ if c['StyleID']
227
+ style_name = c['StyleID']
228
+ elsif
229
+ style_name ||= column_attributes[c['Index']]
230
+ end
231
+ c.xpath('./ss:Data').each do |cell|
232
+ formula = cell['Formula']
233
+ value_type = cell['Type'].downcase.to_sym
234
+ v = cell.content
235
+ str_v = v
236
+ case value_type
237
+ when :number
238
+ v = v.to_f
239
+ value_type = :float
240
+ when :datetime
241
+ if v =~ /^1899-12-31T(\d{2}:\d{2}:\d{2})/
242
+ v = $1
243
+ value_type = :time
244
+ elsif v =~ /([^T]+)T00:00:00.000/
245
+ v = $1
246
+ value_type = :date
247
+ end
248
+ when :boolean
249
+ v = cell['boolean-value']
250
+ end
251
+ set_cell_values(sheet,col,row,0,v,value_type,formula,cell,str_v,style_name)
252
+ end
253
+ col += 1
254
+ end
255
+ row += 1
256
+ col = 1
257
+ end
258
+ end
259
+ if !sheet_found
260
+ raise RangeError, "Unable to find sheet #{sheet} for reading"
261
+ end
262
+ @cells_read[sheet] = true
263
+ end
264
+
265
+ def read_styles
266
+ @doc.xpath("/ss:Workbook/ss:Styles/ss:Style").each do |style|
267
+ style_id = style['ID']
268
+ @style_definitions[style_id] = Roo::Excel2003XML::Font.new
269
+ if font = style.at_xpath('./ss:Font')
270
+ @style_definitions[style_id].bold = font['Bold']
271
+ @style_definitions[style_id].italic = font['Italic']
272
+ @style_definitions[style_id].underline = font['Underline']
273
+ end
274
+ end
275
+ end
276
+
277
+ A_ROO_TYPE = {
278
+ "float" => :float,
279
+ "string" => :string,
280
+ "date" => :date,
281
+ "percentage" => :percentage,
282
+ "time" => :time,
283
+ }
284
+
285
+ def self.oo_type_2_roo_type(ootype)
286
+ return A_ROO_TYPE[ootype]
287
+ end
288
+
289
+ # helper method to convert compressed spaces and other elements within
290
+ # an text into a string
291
+ def children_to_string(children)
292
+ result = ''
293
+ children.each {|child|
294
+ if child.text?
295
+ result = result + child.content
296
+ else
297
+ if child.name == 's'
298
+ compressed_spaces = child['c'].to_i
299
+ # no explicit number means a count of 1:
300
+ if compressed_spaces == 0
301
+ compressed_spaces = 1
302
+ end
303
+ result = result + " "*compressed_spaces
304
+ else
305
+ result = result + child.content
306
+ end
307
+ end
308
+ }
309
+ result
310
+ end
311
+
312
+ end # class
data/lib/roo/excelx.rb CHANGED
@@ -12,7 +12,7 @@ if RUBY_VERSION < '1.9.0'
12
12
  end
13
13
  end
14
14
 
15
- class Excelx < GenericSpreadsheet
15
+ class Roo::Excelx < Roo::GenericSpreadsheet
16
16
  FORMATS = {
17
17
  'General' => :float,
18
18
  '0' => :float,
@@ -51,7 +51,7 @@ class Excelx < GenericSpreadsheet
51
51
  'yyyy-mm-dd' => :date, # 2011-09-16
52
52
  # was used in a spreadsheet file from a windows phone
53
53
  }
54
- STANDARD_FORMATS = {
54
+ STANDARD_FORMATS = {
55
55
  0 => 'General',
56
56
  1 => '0',
57
57
  2 => '0.00',
@@ -81,62 +81,50 @@ class Excelx < GenericSpreadsheet
81
81
  48 => '##0.0E+0',
82
82
  49 => '@',
83
83
  }
84
- @@nr = 0
85
84
 
86
85
  # initialization and opening of a spreadsheet file
87
86
  # values for packed: :zip
88
87
  def initialize(filename, packed=nil, file_warning = :error) #, create = false)
89
- super()
90
- @file_warning = file_warning
91
- file_type_check(filename,'.xlsx','an Excel-xlsx',packed)
92
- @tmpdir = GenericSpreadsheet.next_tmpdir
93
- @tmpdir = File.join(ENV['ROO_TMP'], @tmpdir) if ENV['ROO_TMP']
94
- unless File.exists?(@tmpdir)
95
- FileUtils::mkdir(@tmpdir)
96
- end
97
- filename = open_from_uri(filename) if filename[0,7] == "http://"
98
- filename = unzip(filename) if packed and packed == :zip
99
- @cells_read = Hash.new
100
- @filename = filename
101
- unless File.file?(@filename)
102
- FileUtils::rm_r(@tmpdir)
103
- raise IOError, "file #{@filename} does not exist"
104
- end
105
- @@nr += 1
106
- @file_nr = @@nr
107
- @comments_files = Array.new
108
- extract_content(@filename)
109
- file = File.new(File.join(@tmpdir, @file_nr.to_s+"_roo_workbook.xml"))
110
- @workbook_doc = Nokogiri::XML(file)
111
- file.close
112
- @shared_table = []
113
- if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml'))
114
- file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml'))
115
- @sharedstring_doc = Nokogiri::XML(file)
116
- file.close
117
- read_shared_strings(@sharedstring_doc)
118
- end
119
- @styles_table = []
120
- @style_definitions = Array.new # TODO: ??? { |h,k| h[k] = {} }
121
- if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
122
- file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml'))
123
- @styles_doc = Nokogiri::XML(file)
124
- file.close
125
- read_styles(@styles_doc)
126
- end
127
- @sheet_doc = []
128
- @sheet_files.each_with_index do |item, i|
129
- file = File.new(item)
130
- @sheet_doc[i] = Nokogiri::XML(file)
131
- file.close
132
- end
133
- @comments_doc = []
134
- @comments_files.each_with_index do |item, i|
135
- file = File.new(item)
136
- @comments_doc[i] = Nokogiri::XML(file)
137
- file.close
88
+ file_type_check(filename,'.xlsx','an Excel-xlsx', file_warning, packed)
89
+ make_tmpdir do |tmpdir|
90
+ filename = open_from_uri(filename, tmpdir) if uri?(filename)
91
+ filename = unzip(filename, tmpdir) if packed == :zip
92
+ @cells_read = Hash.new
93
+ @filename = filename
94
+ unless File.file?(@filename)
95
+ raise IOError, "file #{@filename} does not exist"
96
+ end
97
+ @comments_files = Array.new
98
+ extract_content(tmpdir, @filename)
99
+ @workbook_doc = File.open(File.join(tmpdir, "roo_workbook.xml")) do |file|
100
+ Nokogiri::XML(file)
101
+ end
102
+ @shared_table = []
103
+ if File.exist?(File.join(tmpdir, 'roo_sharedStrings.xml'))
104
+ @sharedstring_doc = File.open(File.join(tmpdir, 'roo_sharedStrings.xml')) do |file|
105
+ Nokogiri::XML(file)
106
+ end
107
+ read_shared_strings(@sharedstring_doc)
108
+ end
109
+ @styles_table = []
110
+ @style_definitions = Array.new # TODO: ??? { |h,k| h[k] = {} }
111
+ if File.exist?(File.join(tmpdir, 'roo_styles.xml'))
112
+ @styles_doc = File.open(File.join(tmpdir, 'roo_styles.xml')) do |file|
113
+ Nokogiri::XML(file)
114
+ end
115
+ read_styles(@styles_doc)
116
+ end
117
+ @sheet_doc = @sheet_files.map do |item|
118
+ File.open(item) do |file|
119
+ Nokogiri::XML(file)
120
+ end
121
+ end
122
+ @comments_doc = @comments_files.map do |item|
123
+ File.open(item) do |file|
124
+ Nokogiri::XML(file)
125
+ end
126
+ end
138
127
  end
139
- FileUtils::rm_r(@tmpdir)
140
128
  @default_sheet = self.sheets.first
141
129
  @cell = Hash.new
142
130
  @cell_type = Hash.new
@@ -149,17 +137,15 @@ class Excelx < GenericSpreadsheet
149
137
  @excelx_type = Hash.new
150
138
  @excelx_value = Hash.new
151
139
  @s_attribute = Hash.new # TODO: ggf. wieder entfernen nur lokal benoetigt
152
- @label = Hash.new
153
- @labels_read = false
154
140
  @comment = Hash.new
155
141
  @comments_read = Hash.new
156
142
  end
157
143
 
158
144
  def method_missing(m,*args)
159
145
  # is method name a label name
160
- read_labels unless @labels_read
146
+ read_labels
161
147
  if @label.has_key?(m.to_s)
162
- sheet = @default_sheet unless sheet
148
+ sheet ||= @default_sheet
163
149
  read_cells(sheet) unless @cells_read[sheet]
164
150
  row,col = label(m.to_s)
165
151
  cell(row,col)
@@ -168,13 +154,13 @@ class Excelx < GenericSpreadsheet
168
154
  super
169
155
  end
170
156
  end
171
-
157
+
172
158
  # Returns the content of a spreadsheet-cell.
173
159
  # (1,1) is the upper left corner.
174
160
  # (1,1), (1,'A'), ('A',1), ('a',1) all refers to the
175
161
  # cell at the first line and first row.
176
162
  def cell(row, col, sheet=nil)
177
- sheet = @default_sheet unless sheet
163
+ sheet ||= @default_sheet
178
164
  read_cells(sheet) unless @cells_read[sheet]
179
165
  row,col = normalize(row,col)
180
166
  if celltype(row,col,sheet) == :date
@@ -193,7 +179,7 @@ class Excelx < GenericSpreadsheet
193
179
  # Returns nil if there is no formula.
194
180
  # The method #formula? checks if there is a formula.
195
181
  def formula(row,col,sheet=nil)
196
- sheet = @default_sheet unless sheet
182
+ sheet ||= @default_sheet
197
183
  read_cells(sheet) unless @cells_read[sheet]
198
184
  row,col = normalize(row,col)
199
185
  if @formula[sheet][[row,col]] == nil
@@ -205,7 +191,7 @@ class Excelx < GenericSpreadsheet
205
191
 
206
192
  # true, if there is a formula
207
193
  def formula?(row,col,sheet=nil)
208
- sheet = @default_sheet unless sheet
194
+ sheet ||= @default_sheet
209
195
  read_cells(sheet) unless @cells_read[sheet]
210
196
  row,col = normalize(row,col)
211
197
  formula(row,col) != nil
@@ -214,7 +200,7 @@ class Excelx < GenericSpreadsheet
214
200
  # returns each formula in the selected sheet as an array of elements
215
201
  # [row, col, formula]
216
202
  def formulas(sheet=nil)
217
- sheet = @default_sheet unless sheet
203
+ sheet ||= @default_sheet
218
204
  read_cells(sheet) unless @cells_read[sheet]
219
205
  if @formula[sheet]
220
206
  @formula[sheet].each.collect do |elem|
@@ -227,47 +213,29 @@ class Excelx < GenericSpreadsheet
227
213
 
228
214
  class Font
229
215
  attr_accessor :bold, :italic, :underline
230
-
216
+
231
217
  def bold?
232
218
  @bold == true
233
219
  end
234
-
235
- def italic?
220
+
221
+ def italic?
236
222
  @italic == true
237
223
  end
238
-
224
+
239
225
  def underline?
240
226
  @underline == true
241
- end
227
+ end
242
228
  end
243
-
229
+
244
230
  # Given a cell, return the cell's style
245
231
  def font(row, col, sheet=nil)
246
- sheet = @default_sheet unless sheet
232
+ sheet ||= @default_sheet
247
233
  read_cells(sheet) unless @cells_read[sheet]
248
234
  row,col = normalize(row,col)
249
235
  s_attribute = @s_attribute[sheet][[row,col]]
250
236
  s_attribute ||= 0
251
237
  s_attribute = s_attribute.to_i
252
238
  @style_definitions[s_attribute]
253
- end
254
-
255
- # set a cell to a certain value
256
- # (this will not be saved back to the spreadsheet file!)
257
- def set(row,col,value,sheet=nil) #:nodoc:
258
- sheet = @default_sheet unless sheet
259
- read_cells(sheet) unless @cells_read[sheet]
260
- row,col = normalize(row,col)
261
- set_value(row,col,value,sheet)
262
- if value.class == Fixnum
263
- set_type(row,col,:float,sheet)
264
- elsif value.class == String
265
- set_type(row,col,:string,sheet)
266
- elsif value.class == Float
267
- set_type(row,col,:string,sheet)
268
- else
269
- raise ArgumentError, "Type for "+value.to_s+" not set"
270
- end
271
239
  end
272
240
 
273
241
  # returns the type of a cell:
@@ -279,7 +247,7 @@ class Excelx < GenericSpreadsheet
279
247
  # * :time
280
248
  # * :datetime
281
249
  def celltype(row,col,sheet=nil)
282
- sheet = @default_sheet unless sheet
250
+ sheet ||= @default_sheet
283
251
  read_cells(sheet) unless @cells_read[sheet]
284
252
  row,col = normalize(row,col)
285
253
  if @formula[sheet][[row,col]]
@@ -291,47 +259,44 @@ class Excelx < GenericSpreadsheet
291
259
 
292
260
  # returns the internal type of an excel cell
293
261
  # * :numeric_or_formula
294
- # * :string
295
- # Note: this is only available within the Excelx class
262
+ # * :string
263
+ # Note: this is only available within the Excelx class
296
264
  def excelx_type(row,col,sheet=nil)
297
- sheet = @default_sheet unless sheet
265
+ sheet ||= @default_sheet
298
266
  read_cells(sheet) unless @cells_read[sheet]
299
267
  row,col = normalize(row,col)
300
268
  return @excelx_type[sheet][[row,col]]
301
269
  end
302
-
270
+
303
271
  # returns the internal value of an excelx cell
304
- # Note: this is only available within the Excelx class
272
+ # Note: this is only available within the Excelx class
305
273
  def excelx_value(row,col,sheet=nil)
306
- sheet = @default_sheet unless sheet
274
+ sheet ||= @default_sheet
307
275
  read_cells(sheet) unless @cells_read[sheet]
308
276
  row,col = normalize(row,col)
309
277
  return @excelx_value[sheet][[row,col]]
310
278
  end
311
-
279
+
312
280
  # returns the internal format of an excel cell
313
281
  def excelx_format(row,col,sheet=nil)
314
- sheet = @default_sheet unless sheet
282
+ sheet ||= @default_sheet
315
283
  read_cells(sheet) unless @cells_read[sheet]
316
284
  row,col = normalize(row,col)
317
285
  s = @s_attribute[sheet][[row,col]]
318
- result = attribute2format(s).to_s
319
- result
286
+ attribute2format(s).to_s
320
287
  end
321
-
288
+
322
289
  # returns an array of sheet names in the spreadsheet
323
290
  def sheets
324
- return_sheets = []
325
- @workbook_doc.xpath("//*[local-name()='sheet']").each do |sheet|
326
- return_sheets << sheet['name']
291
+ @workbook_doc.xpath("//xmlns:sheet").map do |sheet|
292
+ sheet['name']
327
293
  end
328
- return_sheets
329
294
  end
330
295
 
331
296
  # shows the internal representation of all cells
332
297
  # for debugging purposes
333
298
  def to_s(sheet=nil)
334
- sheet = @default_sheet unless sheet
299
+ sheet ||= @default_sheet
335
300
  read_cells(sheet) unless @cells_read[sheet]
336
301
  @cell[sheet].inspect
337
302
  end
@@ -339,40 +304,35 @@ class Excelx < GenericSpreadsheet
339
304
  # returns the row,col values of the labelled cell
340
305
  # (nil,nil) if label is not defined
341
306
  def label(labelname)
342
- read_labels unless @labels_read
343
- unless @label.size > 0
307
+ read_labels
308
+ if @label.empty? || !@label.has_key?(labelname)
344
309
  return nil,nil,nil
345
- end
346
- if @label.has_key? labelname
310
+ else
347
311
  return @label[labelname][1].to_i,
348
- GenericSpreadsheet.letter_to_number(@label[labelname][2]),
312
+ Roo::GenericSpreadsheet.letter_to_number(@label[labelname][2]),
349
313
  @label[labelname][0]
350
- else
351
- return nil,nil,nil
352
314
  end
353
315
  end
354
316
 
355
317
  # Returns an array which all labels. Each element is an array with
356
- # [labelname, [sheetname,row,col]]
318
+ # [labelname, [row,col,sheetname]]
357
319
  def labels
358
- # sheet = @default_sheet unless sheet
320
+ # sheet ||= @default_sheet
359
321
  # read_cells(sheet) unless @cells_read[sheet]
360
- read_labels unless @labels_read
361
- result = []
362
- @label.each do |label|
363
- result << [ label[0], # name
322
+ read_labels
323
+ @label.map do |label|
324
+ [ label[0], # name
364
325
  [ label[1][1].to_i, # row
365
- GenericSpreadsheet.letter_to_number(label[1][2]), # column
326
+ Roo::GenericSpreadsheet.letter_to_number(label[1][2]), # column
366
327
  label[1][0], # sheet
367
328
  ] ]
368
329
  end
369
- result
370
330
  end
371
331
 
372
332
  # returns the comment at (row/col)
373
333
  # nil if there is no comment
374
334
  def comment(row,col,sheet=nil)
375
- sheet = @default_sheet unless sheet
335
+ sheet ||= @default_sheet
376
336
  #read_cells(sheet) unless @cells_read[sheet]
377
337
  read_comments(sheet) unless @comments_read[sheet]
378
338
  row,col = normalize(row,col)
@@ -382,7 +342,7 @@ class Excelx < GenericSpreadsheet
382
342
 
383
343
  # true, if there is a comment
384
344
  def comment?(row,col,sheet=nil)
385
- sheet = @default_sheet unless sheet
345
+ sheet ||= @default_sheet
386
346
  # read_cells(sheet) unless @cells_read[sheet]
387
347
  read_comments(sheet) unless @comments_read[sheet]
388
348
  row,col = normalize(row,col)
@@ -392,7 +352,7 @@ class Excelx < GenericSpreadsheet
392
352
  # returns each comment in the selected sheet as an array of elements
393
353
  # [row, col, comment]
394
354
  def comments(sheet=nil)
395
- sheet = @default_sheet unless sheet
355
+ sheet ||= @default_sheet
396
356
  read_comments(sheet) unless @comments_read[sheet]
397
357
  if @comment[sheet]
398
358
  @comment[sheet].each.collect do |elem|
@@ -406,37 +366,38 @@ class Excelx < GenericSpreadsheet
406
366
  private
407
367
 
408
368
  # helper function to set the internal representation of cells
409
- def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v,
369
+ def set_cell_values(sheet,x,y,i,v,value_type,formula,
410
370
  excelx_type=nil,
411
371
  excelx_value=nil,
412
372
  s_attribute=nil)
413
373
  key = [y,x+i]
414
- @cell_type[sheet] = {} unless @cell_type[sheet]
415
- @cell_type[sheet][key] = vt
416
- @formula[sheet] = {} unless @formula[sheet]
374
+ @cell_type[sheet] ||= {}
375
+ @cell_type[sheet][key] = value_type
376
+ @formula[sheet] ||= {}
417
377
  @formula[sheet][key] = formula if formula
418
- @cell[sheet] = {} unless @cell[sheet]
419
- case @cell_type[sheet][key]
420
- when :float
421
- @cell[sheet][key] = v.to_f
422
- when :string
423
- @cell[sheet][key] = str_v
424
- when :date
425
- @cell[sheet][key] = (Date.new(1899,12,30)+v.to_i).strftime("%Y-%m-%d")
426
- when :datetime
427
- @cell[sheet][key] = (DateTime.new(1899,12,30)+v.to_f).strftime("%Y-%m-%d %H:%M:%S")
428
- when :percentage
429
- @cell[sheet][key] = v.to_f
430
- when :time
431
- @cell[sheet][key] = v.to_f*(24*60*60)
432
- else
433
- @cell[sheet][key] = v
434
- end
435
- @excelx_type[sheet] = {} unless @excelx_type[sheet]
378
+ @cell[sheet] ||= {}
379
+ @cell[sheet][key] =
380
+ case @cell_type[sheet][key]
381
+ when :float
382
+ v.to_f
383
+ when :string
384
+ v
385
+ when :date
386
+ (Date.new(1899,12,30)+v.to_i).strftime("%Y-%m-%d")
387
+ when :datetime
388
+ (DateTime.new(1899,12,30)+v.to_f).strftime("%Y-%m-%d %H:%M:%S")
389
+ when :percentage
390
+ v.to_f
391
+ when :time
392
+ v.to_f*(24*60*60)
393
+ else
394
+ v
395
+ end
396
+ @excelx_type[sheet] ||= {}
436
397
  @excelx_type[sheet][key] = excelx_type
437
- @excelx_value[sheet] = {} unless @excelx_value[sheet]
398
+ @excelx_value[sheet] ||= {}
438
399
  @excelx_value[sheet][key] = excelx_value
439
- @s_attribute[sheet] = {} unless @s_attribute[sheet]
400
+ @s_attribute[sheet] ||= {}
440
401
  @s_attribute[sheet][key] = s_attribute
441
402
  end
442
403
 
@@ -451,107 +412,87 @@ class Excelx < GenericSpreadsheet
451
412
 
452
413
  # read all cells in the selected sheet
453
414
  def read_cells(sheet=nil)
454
- sheet = @default_sheet unless sheet
455
- sheet_found = false
456
- raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
457
- raise RangeError unless self.sheets.include? sheet
458
- n = self.sheets.index(sheet)
459
- @sheet_doc[n].xpath("//*[local-name()='c']").each do |c|
415
+ sheet ||= @default_sheet
416
+ validate_sheet!(sheet)
417
+ @sheet_doc[sheets.index(sheet)].xpath("/xmlns:worksheet/xmlns:sheetData/xmlns:row/xmlns:c").each do |c|
460
418
  s_attribute = c['s'].to_i # should be here
461
419
  # c: <c r="A5" s="2">
462
420
  # <v>22606</v>
463
421
  # </c>, format: , tmp_type: float
464
- if c['t'] == 's'
465
- tmp_type = :shared
466
- elsif c['t'] == 'b'
467
- tmp_type = :boolean
468
- # 2011-02-25 BEGIN
469
- elsif c['t'] == 'str'
470
- tmp_type = :string
471
- # 2011-02-25 END
472
- # 2011-09-15 BEGIN
473
- elsif c['t'] == 'inlineStr'
474
- tmp_type = :inlinestr
475
- # 2011-09-15 END
476
- else
477
- s_attribute = c['s'].to_i
478
- format = attribute2format(s_attribute)
479
- tmp_type = format2type(format)
480
- end
422
+ value_type =
423
+ case c['t']
424
+ when 's'
425
+ :shared
426
+ when 'b'
427
+ :boolean
428
+ # 2011-02-25 BEGIN
429
+ when 'str'
430
+ :string
431
+ # 2011-02-25 END
432
+ # 2011-09-15 BEGIN
433
+ when 'inlineStr'
434
+ :inlinestr
435
+ # 2011-09-15 END
436
+ else
437
+ format = attribute2format(s_attribute)
438
+ format2type(format)
439
+ end
481
440
  formula = nil
482
441
  c.children.each do |cell|
483
- # 2011-09-15 BEGIN
484
- if cell.name == 'is'
442
+ case cell.name
443
+ when 'is'
485
444
  cell.children.each do |is|
486
445
  if is.name == 't'
487
446
  inlinestr_content = is.content
488
- vt = :string
489
- str_v = inlinestr_content
447
+ value_type = :string
448
+ v = inlinestr_content
490
449
  excelx_type = :string
491
- y, x = GenericSpreadsheet.split_coordinate(c['r'])
492
- v = nil
493
- tr=nil #TODO: ???s
450
+ y, x = Roo::GenericSpreadsheet.split_coordinate(c['r'])
494
451
  excelx_value = inlinestr_content #cell.content
495
- set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,excelx_type,excelx_value,s_attribute)
452
+ set_cell_values(sheet,x,y,0,v,value_type,formula,excelx_type,excelx_value,s_attribute)
496
453
  end
497
454
  end
498
- end
499
- # 2011-09-15 END
500
- if cell.name == 'f'
455
+ when 'f'
501
456
  formula = cell.content
502
- end
503
- if cell.name == 'v'
504
- if tmp_type == :time or tmp_type == :datetime
505
- if cell.content.to_f >= 1.0
506
- if (cell.content.to_f - cell.content.to_f.floor).abs > 0.000001
507
- tmp_type = :datetime
457
+ when 'v'
458
+ if [:time, :datetime].include?(value_type) && cell.content.to_f >= 1.0
459
+ value_type =
460
+ if (cell.content.to_f - cell.content.to_f.floor).abs > 0.000001
461
+ :datetime
508
462
  else
509
- tmp_type = :date
463
+ :date
510
464
  end
511
- else
512
- end
513
465
  end
514
466
  excelx_type = [:numeric_or_formula,format.to_s]
515
467
  excelx_value = cell.content
516
- if tmp_type == :shared
517
- vt = :string
518
- str_v = @shared_table[cell.content.to_i]
519
- excelx_type = :string
520
- elsif tmp_type == :boolean
521
- vt = :boolean
522
- cell.content.to_i == 1 ? v = 'TRUE' : v = 'FALSE'
523
- elsif tmp_type == :date
524
- vt = :date
525
- v = cell.content
526
- elsif tmp_type == :time
527
- vt = :time
528
- v = cell.content
529
- elsif tmp_type == :datetime
530
- vt = :datetime
531
- v = cell.content
532
- elsif tmp_type == :formula
533
- vt = :formula
534
- v = cell.content.to_f #TODO: !!!!
535
- # 2011-02-25 BEGIN
536
- elsif tmp_type == :string
537
- vt = :string
538
- str_v = cell.content
539
- excelx_type = :string
540
- # 2011-02-25 END
541
- else
542
- vt = :float
543
- v = cell.content
544
- end
545
- y, x = GenericSpreadsheet.split_coordinate(c['r'])
546
- tr=nil #TODO: ???s
547
- set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,excelx_type,excelx_value,s_attribute)
468
+ v =
469
+ case value_type
470
+ when :shared
471
+ value_type = :string
472
+ excelx_type = :string
473
+ @shared_table[cell.content.to_i]
474
+ when :boolean
475
+ (cell.content.to_i == 1 ? 'TRUE' : 'FALSE')
476
+ when :date
477
+ cell.content
478
+ when :time
479
+ cell.content
480
+ when :datetime
481
+ cell.content
482
+ when :formula
483
+ cell.content.to_f #TODO: !!!!
484
+ when :string
485
+ excelx_type = :string
486
+ cell.content
487
+ else
488
+ value_type = :float
489
+ cell.content
490
+ end
491
+ y, x = Roo::GenericSpreadsheet.split_coordinate(c['r'])
492
+ set_cell_values(sheet,x,y,0,v,value_type,formula,excelx_type,excelx_value,s_attribute)
548
493
  end
549
494
  end
550
495
  end
551
- sheet_found = true #TODO:
552
- if !sheet_found
553
- raise RangeError
554
- end
555
496
  @cells_read[sheet] = true
556
497
  # begin comments
557
498
  =begin
@@ -599,71 +540,37 @@ Datei xl/comments1.xml
599
540
 
600
541
  # Reads all comments from a sheet
601
542
  def read_comments(sheet=nil)
602
- sheet = @default_sheet unless sheet
603
- #sheet_found = false
604
- raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
605
- raise RangeError unless self.sheets.include? sheet
543
+ sheet ||= @default_sheet
544
+ validate_sheet!(sheet)
606
545
  n = self.sheets.index(sheet)
607
546
  return unless @comments_doc[n] #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
608
- @comments_doc[n].xpath("//*[local-name()='comments']").each do |comment|
609
- comment.children.each do |cc|
610
- if cc.name == 'commentList'
611
- cc.children.each do |commentlist|
612
- if commentlist.name == 'comment'
613
- ref = commentlist.attributes['ref'].to_s
614
- row,col = GenericSpreadsheet.split_coordinate(ref)
615
- commentlist.children.each do |clc|
616
- if clc.name == 'text'
617
- clc.children.each do |text|
618
- if text.name == 'r'
619
- text.children.each do |r|
620
- if r.name == 't'
621
- comment = r.text
622
- @comment[sheet] = Hash.new unless @comment[sheet]
623
- @comment[sheet][[row,col]] = comment
624
- end
625
- end
626
- end
627
- end
628
- end
629
- end
630
- end
631
- end
632
- end
547
+ @comments_doc[n].xpath("//xmlns:comments/xmlns:commentList/xmlns:comment").each do |comment|
548
+ ref = comment.attributes['ref'].to_s
549
+ row,col = Roo::GenericSpreadsheet.split_coordinate(ref)
550
+ comment.xpath('./xmlns:text/xmlns:r/xmlns:t').each do |text|
551
+ @comment[sheet] ||= {}
552
+ @comment[sheet][[row,col]] = text.text
633
553
  end
634
554
  end
635
555
  @comments_read[sheet] = true
636
556
  end
637
557
 
638
558
  def read_labels
639
- @workbook_doc.xpath("//*[local-name()='definedName']").each do |defined_name|
559
+ @label ||= Hash[@workbook_doc.xpath("//xmlns:definedName").map do |defined_name|
640
560
  # "Sheet1!$C$5"
641
- sheet = defined_name.text.split('!').first
642
- coordinates = defined_name.text.split('!')[1]
643
- dummy,col,row = coordinates.split('$')
644
- @label[defined_name['name']] = [sheet,row,col]
645
- end
646
- @labels_read = true
647
- end
648
-
649
- # Checks if the default_sheet exists. If not an RangeError exception is
650
- # raised
651
- def check_default_sheet
652
- sheet_found = false
653
- raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil
654
- sheet_found = true if sheets.include?(@default_sheet)
655
- if ! sheet_found
656
- raise RangeError, "sheet '#{@default_sheet}' not found"
657
- end
561
+ sheet, coordinates = defined_name.text.split('!$', 2)
562
+ col,row = coordinates.split('$')
563
+ [defined_name['name'], [sheet,row,col]]
564
+ end]
658
565
  end
659
566
 
660
567
  # Extracts all needed files from the zip file
661
- def process_zipfile(zipfilename, zip, path='')
568
+ def process_zipfile(tmpdir, zipfilename, zip, path='')
662
569
  @sheet_files = []
663
570
  Zip::ZipFile.open(zipfilename) {|zf|
664
571
  zf.entries.each {|entry|
665
572
  if entry.to_s.end_with?('workbook.xml')
666
- open(@tmpdir+'/'+@file_nr.to_s+'_roo_workbook.xml','wb') {|f|
573
+ open(tmpdir+'/'+'roo_workbook.xml','wb') {|f|
667
574
  f << zip.read(entry)
668
575
  }
669
576
  end
@@ -673,28 +580,28 @@ Datei xl/comments1.xml
673
580
  # won't be both names in the archive.
674
581
  # Changed the casing of all the following filenames.
675
582
  if entry.to_s.downcase.end_with?('sharedstrings.xml')
676
- open(@tmpdir+'/'+@file_nr.to_s+'_roo_sharedStrings.xml','wb') {|f|
583
+ open(tmpdir+'/'+'roo_sharedStrings.xml','wb') {|f|
677
584
  f << zip.read(entry)
678
585
  }
679
586
  end
680
587
  if entry.to_s.downcase.end_with?('styles.xml')
681
- open(@tmpdir+'/'+@file_nr.to_s+'_roo_styles.xml','wb') {|f|
588
+ open(tmpdir+'/'+'roo_styles.xml','wb') {|f|
682
589
  f << zip.read(entry)
683
590
  }
684
591
  end
685
592
  if entry.to_s.downcase =~ /sheet([0-9]+).xml$/
686
593
  nr = $1
687
- open(@tmpdir+'/'+@file_nr.to_s+"_roo_sheet#{nr}",'wb') {|f|
594
+ open(tmpdir+'/'+"roo_sheet#{nr}",'wb') {|f|
688
595
  f << zip.read(entry)
689
596
  }
690
- @sheet_files[nr.to_i-1] = @tmpdir+'/'+@file_nr.to_s+"_roo_sheet#{nr}"
597
+ @sheet_files[nr.to_i-1] = tmpdir+'/'+"roo_sheet#{nr}"
691
598
  end
692
599
  if entry.to_s.downcase =~ /comments([0-9]+).xml$/
693
600
  nr = $1
694
- open(@tmpdir+'/'+@file_nr.to_s+"_roo_comments#{nr}",'wb') {|f|
601
+ open(tmpdir+'/'+"roo_comments#{nr}",'wb') {|f|
695
602
  f << zip.read(entry)
696
603
  }
697
- @comments_files[nr.to_i-1] = @tmpdir+'/'+@file_nr.to_s+"_roo_comments#{nr}"
604
+ @comments_files[nr.to_i-1] = tmpdir+'/'+"roo_comments#{nr}"
698
605
  end
699
606
  }
700
607
  }
@@ -702,27 +609,15 @@ Datei xl/comments1.xml
702
609
  end
703
610
 
704
611
  # extract files from the zip file
705
- def extract_content(zipfilename)
612
+ def extract_content(tmpdir, zipfilename)
706
613
  Zip::ZipFile.open(@filename) do |zip|
707
- process_zipfile(zipfilename,zip)
614
+ process_zipfile(tmpdir, zipfilename,zip)
708
615
  end
709
616
  end
710
617
 
711
- # sets the value of a cell
712
- def set_value(row,col,value,sheet=nil)
713
- sheet = @default_value unless sheet
714
- @cell[sheet][[row,col]] = value
715
- end
716
-
717
- # sets the type of a cell
718
- def set_type(row,col,type,sheet=nil)
719
- sheet = @default_value unless sheet
720
- @cell_type[sheet][[row,col]] = type
721
- end
722
-
723
618
  # read the shared strings xml document
724
619
  def read_shared_strings(doc)
725
- doc.xpath("//*[local-name()='si']").each do |si|
620
+ doc.xpath("/xmlns:sst/xmlns:si").each do |si|
726
621
  shared_table_entry = ''
727
622
  si.children.each do |elem|
728
623
  if elem.name == 'r' and elem.children
@@ -742,62 +637,31 @@ Datei xl/comments1.xml
742
637
 
743
638
  # read the styles elements of an excelx document
744
639
  def read_styles(doc)
745
- @numFmts = []
746
640
  @cellXfs = []
747
- fonts = []
748
-
749
- doc.xpath("//*[local-name()='numFmt']").each do |numFmt|
750
- numFmtId = numFmt.attributes['numFmtId']
751
- formatCode = numFmt.attributes['formatCode']
752
- @numFmts << [numFmtId, formatCode]
753
- end
754
- doc.xpath("//*[local-name()='fonts']").each do |fonts_el|
755
- fonts_el.children.each do |font_el|
756
- if font_el == 'font'
757
- font = Excelx::Font.new
758
- font_el.each_element do |font_sub_el|
759
- case font_sub_el.name
760
- when 'b'
761
- font.bold = true
762
- when 'i'
763
- font.italic = true
764
- when 'u'
765
- font.underline = true
766
- end
767
- end
768
- fonts << font
769
- end
641
+
642
+ @numFmts = Hash[doc.xpath("//xmlns:numFmt").map do |numFmt|
643
+ [numFmt['numFmtId'], numFmt['formatCode']]
644
+ end]
645
+ fonts = doc.xpath("//xmlns:fonts/xmlns:font").map do |font_el|
646
+ Font.new.tap do |font|
647
+ font.bold = !font_el.xpath('./xmlns:b').empty?
648
+ font.italic = !font_el.xpath('./xmlns:i').empty?
649
+ font.underline = !font_el.xpath('./xmlns:u').empty?
770
650
  end
771
651
  end
772
-
773
- doc.xpath("//*[local-name()='cellXfs']").each do |xfs|
652
+
653
+ doc.xpath("//xmlns:cellXfs").each do |xfs|
774
654
  xfs.children.each do |xf|
775
- numFmtId = xf['numFmtId']
776
- @cellXfs << [numFmtId]
777
- fontId = xf['fontId'].to_i
778
- @style_definitions << fonts[fontId]
655
+ @cellXfs << xf['numFmtId']
656
+ @style_definitions << fonts[xf['fontId'].to_i]
779
657
  end
780
658
  end
781
659
  end
782
660
 
783
661
  # convert internal excelx attribute to a format
784
662
  def attribute2format(s)
785
- result = nil
786
- @numFmts.each {|nf|
787
- # to_s weil das eine Nokogiri::XML::Attr und das
788
- # andere ein String ist
789
- if nf.first.to_s == @cellXfs[s.to_i].first
790
- result = nf[1]
791
- break
792
- end
793
- }
794
- unless result
795
- id = @cellXfs[s.to_i].first.to_i
796
- if STANDARD_FORMATS.has_key? id
797
- result = STANDARD_FORMATS[id]
798
- end
799
- end
800
- result
663
+ id = @cellXfs[s.to_i]
664
+ @numFmts[id] || STANDARD_FORMATS[id.to_i]
801
665
  end
802
666
 
803
667
  end # class