Merge remote-tracking branch 'myk002/myk_xlsxreader_classes' into develop

develop
lethosor 2021-03-27 00:10:03 -04:00
commit d61c4aa234
No known key found for this signature in database
GPG Key ID: 76A269552F4F58C1
4 changed files with 116 additions and 66 deletions

@ -4305,41 +4305,69 @@ xlsxreader
========== ==========
Utility functions to facilitate reading .xlsx spreadsheets. It provides the Utility functions to facilitate reading .xlsx spreadsheets. It provides the
following API methods: following low-level API methods:
- ``file_handle open_xlsx_file(filename)`` - ``open_xlsx_file(filename)`` returns a file_handle or nil on error
- ``close_xlsx_file(file_handle)`` - ``close_xlsx_file(file_handle)`` closes the specified file_handle
- ``sheet_names list_sheets(file_handle)`` - ``list_sheets(file_handle)`` returns a list of strings representing sheet
- ``sheet_handle open_sheet(file_handle, sheet_name)`` names
- ``close_sheet(sheet_handle)`` - ``open_sheet(file_handle, sheet_name)`` returns a sheet_handle. This call
- ``cell_strings get_row(sheet_handle)`` always succeeds, even if the sheet doesn't exist. Non-existent sheets will
have no data, though.
- ``close_sheet(sheet_handle)`` closes the specified sheet_handle
- ``get_row(sheet_handle, max_tokens)`` returns a list of strings representing
the contents of the cells in the next row. The ``max_tokens`` parameter is
optional. If set to a number > 0, it limits the number of cells read and
returned for the row.
Example:: The plugin also provides Lua class wrappers for ease of use:
- ``XlsxioReader`` provides access to .xlsx files
- ``XlsxioSheetReader`` provides access to sheets within .xlsx files
- ``open(filepath)`` initializes and returns an ``XlsxioReader`` object
The ``XlsxioReader`` class has the following methods:
- ``XlsxioReader:close()`` closes the file. Be sure to close any open child
sheet handles first!
- ``XlsxioReader:list_sheets()`` returns a list of strings representing sheet
names
- ``XlsxioReader:open_sheet(sheet_name)`` returns an initialized
``XlsxioSheetReader`` object
The ``XlsxioSheetReader`` class has the following methods:
- ``XlsxioSheetReader:close()`` closes the sheet
- ``XlsxioSheetReader:get_row(max_tokens)`` reads the next row from the sheet.
If ``max_tokens`` is specified and is a positive integer, only the first
``max_tokens`` elements of the row are returned.
Here is an end-to-end example::
local xlsxreader = require('plugins.xlsxreader') local xlsxreader = require('plugins.xlsxreader')
local function dump_sheet(xlsx_file, sheet_name) local function dump_sheet(reader, sheet_name)
print('reading sheet: '..sheet_name) print('reading sheet: ' .. sheet_name)
local xlsx_sheet = xlsxreader.open_sheet(xlsx_file, sheet_name) local sheet_reader = reader:open_sheet(sheet_name)
dfhack.with_finalize( dfhack.with_finalize(
function () xlsxreader.close_sheet(xlsx_sheet) end, function() sheet_reader:close() end,
function () function()
local row_cells = xlsxreader.get_row(xlsx_sheet) local row_cells = sheet_reader:get_row()
while row_cells do while row_cells do
printall(row_cells) printall(row_cells)
row_cells = xlsxreader.get_row(xlsx_sheet) row_cells = sheet_reader:get_row()
end end
end end
) )
end end
local filepath = "path/to/some_file.xlsx" local filepath = 'path/to/some_file.xlsx'
local xlsx_file = xlsxreader.open_xlsx_file(filepath) local reader = xlsxreader.open(filepath)
dfhack.with_finalize( dfhack.with_finalize(
function () xlsxreader.close_xlsx_file(xlsx_file) end, function() reader:close() end,
function () function()
for _, sheet_name in ipairs(xlsxreader.list_sheets(xlsx_file)) do for _,sheet_name in ipairs(reader:list_sheets()) do
dump_sheet(xlsx_file, sheet_name) dump_sheet(reader, sheet_name)
end end
end end
) )

@ -33,6 +33,9 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
# Future # Future
## Lua
- `xlsxreader`: Added Lua class wrappers for the xlsxreader plugin API
## Documentation ## Documentation
- Added more client library implementations to the `remote interface docs <remote-client-libs>` - Added more client library implementations to the `remote interface docs <remote-client-libs>`

@ -1,47 +1,59 @@
local _ENV = mkmodule('plugins.xlsxreader') local _ENV = mkmodule('plugins.xlsxreader')
--[[ XlsxioSheetReader = defclass(XlsxioSheetReader, nil)
XlsxioSheetReader.ATTRS{
Native functions: -- handle to the open sheet. required.
sheet_handle = DEFAULT_NIL,
* file_handle open_xlsx_file(filename) }
* close_xlsx_file(file_handle)
* sheet_names list_sheets(file_handle) function XlsxioSheetReader:init()
if not self.sheet_handle then
* sheet_handle open_sheet(file_handle, sheet_name) error('XlsxSheetReader: sheet_handle is required')
* close_sheet(sheet_handle)
* cell_strings get_row(sheet_handle)
Sample usage:
local xlsxreader = require('plugins.xlsxreader')
local function dump_sheet(xlsx_file, sheet_name)
print('reading sheet: '..sheet_name)
local xlsx_sheet = xlsxreader.open_sheet(xlsx_file, sheet_name)
dfhack.with_finalize(
function () xlsxreader.close_sheet(xlsx_sheet) end,
function ()
local row_cells = xlsxreader.get_row(xlsx_sheet)
while row_cells do
printall(row_cells)
row_cells = xlsxreader.get_row(xlsx_sheet)
end
end end
) end
function XlsxioSheetReader:close()
close_sheet(self.sheet_handle)
self.sheet_handle = nil
end
function XlsxioSheetReader:get_row(max_tokens)
return get_row(self.sheet_handle, max_tokens)
end
XlsxioReader = defclass(XlsxioReader, nil)
XlsxioReader.ATTRS{
-- full or relative path to the target .xlsx file. required.
filepath = DEFAULT_NIL,
}
function open(filepath)
return XlsxioReader{filepath=filepath}
end
function XlsxioReader:init()
if not self.filepath then
error('XlsxReader: filepath is required')
end end
self.xlsx_handle = open_xlsx_file(self.filepath)
local filepath = "path/to/some_file.xlsx" if not self.xlsx_handle then
local xlsx_file = xlsxreader.open_xlsx_file(filepath) qerror(('failed to open "%s"'):format(self.filepath))
dfhack.with_finalize(
function () xlsxreader.close_xlsx_file(xlsx_file) end,
function ()
for _, sheet_name in ipairs(xlsxreader.list_sheets(xlsx_file)) do
dump_sheet(xlsx_file, sheet_name)
end end
end end
)
function XlsxioReader:close()
--]] close_xlsx_file(self.xlsx_handle)
self.xlsx_handle = nil
end
function XlsxioReader:list_sheets()
return list_sheets(self.xlsx_handle)
end
-- if sheet_name is empty or nil, opens the first sheet
function XlsxioReader:open_sheet(sheet_name)
local sheet_handle = open_sheet(self.xlsx_handle, sheet_name)
return XlsxioSheetReader{sheet_handle=sheet_handle}
end
return _ENV return _ENV

@ -101,11 +101,13 @@ int list_sheets(lua_State *L) {
return 1; return 1;
} }
// takes the sheet handle and returns a table-list of strings, or nil if we // takes the sheet handle and returns a table-list of strings, limited to the
// already processed the last row in the file. // requested number of tokens if specified and > 0, or nil if we already
// processed the last row in the file.
int get_row(lua_State *L) { int get_row(lua_State *L) {
auto sheet_handle = (xlsx_sheet_handle *)get_xlsxreader_handle(L); auto sheet_handle = (xlsx_sheet_handle *)get_xlsxreader_handle(L);
CHECK_NULL_POINTER(sheet_handle->handle); CHECK_NULL_POINTER(sheet_handle->handle);
lua_Integer max_tokens = luaL_optinteger(L, 2, 0);
bool ok = get_next_row(sheet_handle); bool ok = get_next_row(sheet_handle);
if (!ok) { if (!ok) {
lua_pushnil(L); lua_pushnil(L);
@ -113,8 +115,13 @@ int get_row(lua_State *L) {
std::string value; std::string value;
auto cells = std::vector<std::string>(); auto cells = std::vector<std::string>();
while (get_next_cell(sheet_handle, value)) { while (get_next_cell(sheet_handle, value)) {
// read all cells in the row, even if we don't need to;
// otherwise xlsxio will return a spurious empty row on
// next call
if (max_tokens <= 0 || cells.size() < max_tokens) {
cells.push_back(value); cells.push_back(value);
} }
}
Lua::PushVector(L, cells, true); Lua::PushVector(L, cells, true);
} }