lib/roo/excelx.rb in roo-1.3.11 vs lib/roo/excelx.rb in roo-1.9.0

- old
+ new

@@ -1,13 +1,17 @@ -require 'xml' +#TODO: require 'xml' require 'fileutils' require 'zip/zipfilesystem' require 'date' +require 'rubygems' +require 'nokogiri' -class String - def end_with?(str) - self[-str.length,str.length] == str +if RUBY_VERSION < '1.9.0' + class String + def end_with?(str) + self[-str.length,str.length] == str + end end end class Excelx < GenericSpreadsheet FORMATS = { @@ -98,31 +102,37 @@ end @@nr += 1 @file_nr = @@nr extract_content(@filename) file = File.new(File.join(@tmpdir, @file_nr.to_s+"_roo_workbook.xml")) - @workbook_doc = XML::Parser.io(file).parse + # TODO: @workbook_doc = XML::Parser.io(file).parse + @workbook_doc = Nokogiri::XML(file) + + file.close @shared_table = [] if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml')) file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_sharedStrings.xml')) - @sharedstring_doc = XML::Parser.io(file).parse + #TODO: @sharedstring_doc = XML::Parser.io(file).parse + @sharedstring_doc = Nokogiri::XML(file) file.close read_shared_strings(@sharedstring_doc) end @styles_table = [] - @style_definitions = Array.new { |h,k| h[k] = {} } + @style_definitions = Array.new # TODO: ??? { |h,k| h[k] = {} } if File.exist?(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml')) file = File.new(File.join(@tmpdir, @file_nr.to_s+'_roo_styles.xml')) - @styles_doc = XML::Parser.io(file).parse + #TODO: @styles_doc = XML::Parser.io(file).parse + @styles_doc = Nokogiri::XML(file) file.close read_styles(@styles_doc) end @sheet_doc = [] @sheet_files.each_with_index do |item, i| file = File.new(item) - @sheet_doc[i] = XML::Parser.io(file).parse + #TODO: @sheet_doc[i] = XML::Parser.io(file).parse + @sheet_doc[i] = Nokogiri::XML(file) file.close end ensure #if ENV["roo_local"] != "thomas-p" FileUtils::rm_r(@tmpdir) @@ -190,27 +200,27 @@ def bold? @bold == true end def italic? - @italic == true + @italic == true end def underline? @underline == true end end # Given a cell, return the cell's style def font(row, col, sheet=nil) - sheet = @default_sheet unless sheet - read_cells(sheet) unless @cells_read[sheet] - row,col = normalize(row,col) - s_attribute = @s_attribute[sheet][[row,col]] - s_attribute ||= 0 - s_attribute = s_attribute.to_i - @style_definitions[s_attribute] + sheet = @default_sheet unless sheet + read_cells(sheet) unless @cells_read[sheet] + row,col = normalize(row,col) + s_attribute = @s_attribute[sheet][[row,col]] + s_attribute ||= 0 + s_attribute = s_attribute.to_i + @style_definitions[s_attribute] end # set a cell to a certain value # (this will not be saved back to the spreadsheet file!) def set(row,col,value,sheet=nil) #:nodoc: @@ -279,12 +289,14 @@ end # returns an array of sheet names in the spreadsheet def sheets return_sheets = [] - @workbook_doc.find("//*[local-name()='sheet']").each do |sheet| - return_sheets << sheet.attributes.to_h['name'] + #TODO: @workbook_doc.find("//*[local-name()='sheet']").each do |sheet| + @workbook_doc.xpath("//*[local-name()='sheet']").each do |sheet| + #TODO: return_sheets << sheet.attributes.to_h['name'] + return_sheets << sheet['name'] end return_sheets end # shows the internal representation of all cells # for debugging purposes @@ -372,12 +384,12 @@ x = GenericSpreadsheet.letter_to_number(letter) y = number return x,y end - # read all cells in the selected sheet def format2type(format) + format = format.to_s # weil von Typ Nokogiri::XML::Attr if FORMATS.has_key? format FORMATS[format] else :float end @@ -388,26 +400,38 @@ sheet = @default_sheet unless sheet sheet_found = false raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil raise RangeError unless self.sheets.include? sheet n = self.sheets.index(sheet) - @sheet_doc[n].find("//*[local-name()='c']").each do |c| - s_attribute = c.attributes.to_h['s'].to_i # should be here - if (c.attributes.to_h['t'] == 's') - tmp_type = :shared - elsif (c.attributes.to_h['t'] == 'b') - tmp_type = :boolean - else - # s_attribute = c.attributes.to_h['s'].to_i # was here - format = attribute2format(s_attribute) - tmp_type = format2type(format) - end + #TODO: @sheet_doc[n].find("//*[local-name()='c']").each do |c| + @sheet_doc[n].xpath("//*[local-name()='c']").each do |c| + #TODO: s_attribute = c.attributes.to_h['s'].to_i # should be here + s_attribute = c['s'].to_i # should be here + #TODO: if (c.attributes.to_h['t'] == 's') + # c: <c r="A5" s="2"> + # <v>22606</v> + # </c>, format: , tmp_type: float + + if c['t'] == 's' + tmp_type = :shared + #TODO: elsif (c.attributes.to_h['t'] == 'b') + elsif c['t'] == 'b' + tmp_type = :boolean + else + #s_attribute = c.attributes.to_h['s'].to_i # was here + s_attribute = c['s'].to_i # was here + format = attribute2format(s_attribute) + tmp_type = format2type(format) + end formula = nil - c.each_element do |cell| + #TODO: c.each_element do |cell| + c.children.each do |cell| + #TODO: if cell.name == 'f' if cell.name == 'f' formula = cell.content end + #TODO: if cell.name == 'v' if cell.name == 'v' if tmp_type == :time or tmp_type == :datetime if cell.content.to_f >= 1.0 if (cell.content.to_f - cell.content.to_f.floor).abs > 0.000001 tmp_type = :datetime @@ -415,11 +439,11 @@ tmp_type = :date end else end end - excelx_type = [:numeric_or_formula,format] + excelx_type = [:numeric_or_formula,format.to_s] excelx_value = cell.content if tmp_type == :shared vt = :string str_v = @shared_table[cell.content.to_i] excelx_type = :string @@ -441,11 +465,12 @@ else vt = :float v = cell.content end #puts "vt: #{vt}" if cell.text.include? "22606.5120" - x,y = split_coordinate(c.attributes.to_h['r']) + #TODO: x,y = split_coordinate(c.attributes.to_h['r']) + x,y = split_coordinate(c['r']) tr=nil #TODO: ???s set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,excelx_type,excelx_value,s_attribute) end end end @@ -521,21 +546,23 @@ @cell_type[sheet][[row,col]] = type end # read the shared strings xml document def read_shared_strings(doc) - doc.find("//*[local-name()='si']").each do |si| + #TODO: doc.find("//*[local-name()='si']").each do |si| + doc.xpath("//*[local-name()='si']").each do |si| shared_table_entry = '' - si.each_element do |elem| - if (elem.name == 'r') + #TODO: si.each_element do |elem| + si.children.each do |elem| + if elem.name == 'r' elem.each_element do |r_elem| - if (r_elem.name == 't') + if r_elem.name == 't' shared_table_entry << r_elem.content end end end - if (elem.name == 't') + if elem.name == 't' shared_table_entry = elem.content end end @shared_table << shared_table_entry end @@ -545,48 +572,60 @@ def read_styles(doc) @numFmts = [] @cellXfs = [] fonts = [] - doc.find("//*[local-name()='numFmt']").each do |numFmt| - numFmtId = numFmt.attributes.to_h['numFmtId'] - formatCode = numFmt.attributes.to_h['formatCode'] + #TODO: doc.find("//*[local-name()='numFmt']").each do |numFmt| + doc.xpath("//*[local-name()='numFmt']").each do |numFmt| + # TODO: numFmtId = numFmt.attributes.to_h['numFmtId'] + numFmtId = numFmt.attributes['numFmtId'] + #TODO: formatCode = numFmt.attributes.to_h['formatCode'] + formatCode = numFmt.attributes['formatCode'] @numFmts << [numFmtId, formatCode] end - doc.find("//*[local-name()='fonts']").each do |fonts_el| - fonts_el.each_element do |font_el| - if font_el.name == 'font' + #TODO: doc.find("//*[local-name()='fonts']").each do |fonts_el| + doc.xpath("//*[local-name()='fonts']").each do |fonts_el| + #TODO: fonts_el.each_element do |font_el| + fonts_el.children.each do |font_el| + #TODO: if font_el.name == 'font' + if font_el == 'font' font = Excelx::Font.new font_el.each_element do |font_sub_el| case font_sub_el.name - when 'b' - font.bold = true - when 'i' - font.italic = true - when 'u' - font.underline = true - end + when 'b' + font.bold = true + when 'i' + font.italic = true + when 'u' + font.underline = true + end end fonts << font end end end - doc.find("//*[local-name()='cellXfs']").each do |xfs| - xfs.each do |xf| - numFmtId = xf.attributes.to_h['numFmtId'] - @cellXfs << [numFmtId] - fontId = xf.attributes.to_h['fontId'].to_i - @style_definitions << fonts[fontId] - end + #TODO: doc.find("//*[local-name()='cellXfs']").each do |xfs| + doc.xpath("//*[local-name()='cellXfs']").each do |xfs| + xfs.children.each do |xf| + #TODO: numFmtId = xf.attributes.to_h['numFmtId'] + numFmtId = xf['numFmtId'] + @cellXfs << [numFmtId] + #TODO: fontId = xf.attributes.to_h['fontId'].to_i + fontId = xf['fontId'].to_i + @style_definitions << fonts[fontId] + end end end # convert internal excelx attribute to a format def attribute2format(s) result = nil @numFmts.each {|nf| - if nf.first == @cellXfs[s.to_i].first + #TODO: if nf.first == @cellXfs[s.to_i].first + # to_s weil das eine Nokogiri::XML::Attr und das + # andere ein String ist + if nf.first.to_s == @cellXfs[s.to_i].first result = nf[1] break end } unless result