There’re some libraries dealing with Excel, but they didn’t work in some conditions. So I’ve just written the code for this.
ExcelData uses win32ole module. It means this work only on Windows and Excel needs to be installed.
There’s only a public class method Load returns row array. Each row consists of hash with column name and value string pair.
Load method requires minimum three parameters. Excel filename(excelFilename), sheet name(worksheetName) and first header column name(firstHeaderColumnName). ExcelData finds first row with first header column name and read cell from there. If empty cell is found(both row and column), it stops reading the file.
require 'win32ole'
class ExcelData
public
def ExcelData.Load(excelFilename, worksheetName, firstHeaderColumnName, keySearcher = nil)
xls = nil
ws = nil
excelData = []
begin
xls = WIN32OLE.new('Excel.Application')
xls.visible = false
ws = xls.Workbooks.Open(excelFilename).Worksheets(worksheetName)
excelData = _CollectData(ws, firstHeaderColumnName, keySearcher)
rescue
puts "Failed to open excel file : #{excelFilename}"
ensure
xls.quit if xls != nil
end
return excelData
end
private
def ExcelData._FindFirstDataRowNum(worksheet, firstHeaderColumnName)
rowNum = 1
while (true)
row = worksheet.Range("a#{rowNum}")
break if (row['Value'] != nil && row['Value'] == firstHeaderColumnName)
rowNum += 1
end
return rowNum + 1
end
def ExcelData._FindLastDataRowNum(worksheet, firstDataRowNum)
rowNum = firstDataRowNum
while (true)
row = worksheet.Range("a#{rowNum}")
break if (row['Value'] == nil || row['Value'] == "")
rowNum += 1
end
return rowNum - 1
end
def ExcelData._FindLastDataColChar(worksheet, headerDataRowNum)
colChar = 'a'
while (true)
row = worksheet.Range("#{colChar}#{headerDataRowNum}")
break if (colChar == 'z' || row['Value'] == nil || row['Value'] == "")
colChar.succ!
end
return colChar
end
def ExcelData._CollectData(worksheet, firstHeaderColumnName, keySearcher)
firstDataRowNum = _FindFirstDataRowNum(worksheet, firstHeaderColumnName)
lastDataRowNum = _FindLastDataRowNum(worksheet, firstDataRowNum)
lastDataColChar = _FindLastDataColChar(worksheet, firstDataRowNum - 1)
puts "Collecting excel data : Total #{lastDataRowNum - firstDataRowNum + 1} rows ..."
# Column Names
colNames = []
row = worksheet.Range("a#{firstDataRowNum - 1}:#{lastDataColChar}#{firstDataRowNum - 1}")
row.each do |cell| colNames << cell['Value'] end
# Collect excel data
excelData = []
for rowNum in firstDataRowNum..lastDataRowNum
colIndex = 0
rowHash = {}
row = worksheet.Range("a#{rowNum}:#{lastDataColChar}#{rowNum}")
row.each do |cell|
if (!cell['Value'].to_s.empty? && cell['Value'].to_s =~ /^[0-9.]+/)
rowHash.store(colNames[colIndex], cell['Value'].to_i.to_s)
elsif
rowHash.store(colNames[colIndex], cell['Value'].to_s)
end
colIndex += 1
end
excelData << rowHash
keySearcher.store(rowHash[colNames[0]].to_s, excelData.length - 1) if keySearcher != nil
print "." if excelData.length % 10 == 0
end
puts
return excelData
end
end
You can simply use this code like bellow.
xls = ExcelData.Load('myfile.xls', 'sheet1', 'ITEMID')