Skip to content

Instantly share code, notes, and snippets.

@zauguin
Created June 12, 2021 10:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zauguin/a1c73bf596a08e51d8a9d94f485c8a27 to your computer and use it in GitHub Desktop.
Save zauguin/a1c73bf596a08e51d8a9d94f485c8a27 to your computer and use it in GitHub Desktop.
-- Requires slaxdom and slaxml from https://github.com/Phrogz/SLAXML
local slaxdom = require'slaxdom'
local xlsxNs = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
local relNs = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
local function filteredNext(ns, element)
local function iter(table, i)
i = i + 1
local elem = table[i]
if not elem then
return nil
end
if elem.nsURI == ns and elem.name == element then
return i, elem
end
return iter(table, i)
end
return iter
end
local function elementIter(parent, ns, element)
return filteredNext(ns, element), parent.el, 0
end
local function findAttr(element, ns, attr)
if not attr and ns then ns, attr = attr, ns end
for _,attribute in ipairs(element.attr) do
if attribute.nsURI == ns and attribute.name == attr then
return attribute.value
end
end
end
local function readDom(f, msg)
if not f then return f, msg end
local data = f:read'*a'
f:close()
return slaxdom:dom(data)
end
local f = assert(zip.open'how_should_i_know_how_you_call_your_files.xlsx')
local sheets = {}
local relationships do
local ns = 'http://schemas.openxmlformats.org/package/2006/relationships'
local dom = assert(readDom(f:open'xl/_rels/workbook.xml.rels')).root
relationships = {}
for _, rel in elementIter(dom, ns, 'Relationship') do
relationships[rel.attr.Id] = rel.attr.Target
end
end
local workbook = assert(readDom(f:open'xl/workbook.xml')).root
local worksheets = {}
for _, sheets in elementIter(workbook, xlsxNs, 'sheets') do
for _, sheet in elementIter(sheets, xlsxNs, 'sheet') do
local worksheet = assert(readDom(f:open('xl/' .. relationships[findAttr(sheet, relNs, 'id')]))).root
assert(worksheet.nsURI == xlsxNs and worksheet.name == 'worksheet')
local sheetData
for _, element in elementIter(worksheet, xlsxNs, 'sheetData') do
assert(not sheetData)
sheetData = element
end
assert(sheetData)
local rows = {}
for i, rowElement in elementIter(sheetData, xlsxNs, 'row') do
local row = {}
for j, colElem in elementIter(rowElement, xlsxNs, 'c') do
for _, entry in elementIter(colElem, xlsxNs, 'v') do
local value = entry.kids
if not value or #value == 0 then
value = nil
elseif #value == 1 and value[1].type == 'text' then
value = value[1].value
value = tonumber(value) or value
else
error'???'
end
row[j] = value
break
end
end
rows[i] = row
end
worksheets[sheet.attr.name] = rows
end
break
end
print(worksheets.Sheet1[5][2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment