WKS to JSONLotus 1-2-3
Lotus 1-2-3 workbooks.
Files from Lotus 1-2-3, the dominant spreadsheet before Excel. TabularJS reads cell values from WKS, WK1, WK3, WK4 and .123 files, including the sheet names of multi-sheet workbooks.
WKS (Lotus 1-2-3 release 1) and WK1 (release 2) files are binary lists of records, each with a type, a length and a payload. Cell records carry the column, the row, a format byte and the value: an integer, a floating-point number, a text label, or a formula together with its last calculated result.
TabularJS walks those records and builds a worksheet from them, in Node.js or the browser. It is meant for getting archived models and old business data out of Lotus files and into JSON, a database or a modern spreadsheet.
Feature support
Formula cells return the value Lotus saved with them; the formula itself is not decoded.
What TabularJS extracts from WKS files
- Numbers and labels in
data[row][col]: one worksheet namedSheet1for WKS and WK1 files, and one worksheet per sheet, with its name, for WK3, WK4 and .123 workbooks. - Notes in .123 files as
worksheet.comments, and error and N/A cells as#ERR!and#N/A. - Formula cells as their calculated value: a number, or the text of a string result.
- Label alignment prefixes (
'left,"right,^center) astext-alignCSS inworksheet.style. Cells whose format byte has the protection bit set also getpointer-events: none. - Column widths from the column width records.
Convert WKS to JSON in Node.js
import tabularjs from 'tabularjs';
const result = await tabularjs('budget.wk1');
console.log(result.worksheets[0].worksheetName); // 'Sheet1'
console.log(result.worksheets[0].data);
// [ [ 'Item', 'Amount' ], [ 'Rent', 900 ], [ 'Power', 75.5 ], [ 'Total', 975.5 ] ]
// WK3, WK4 and .123 workbooks: one worksheet per sheet
const plan = await tabularjs('plan.123');
for (const sheet of plan.worksheets) {
console.log(sheet.worksheetName, sheet.data.length, 'rows');
}Read WKS files in the browser
import tabularjs from 'tabularjs';
const input = document.querySelector('input[type=file]');
input.addEventListener('change', async () => {
const result = await tabularjs(input.files[0]);
for (const sheet of result.worksheets) {
console.log(sheet.worksheetName, sheet.data);
}
});JSON output
{
"worksheets": [
{
"worksheetName": "Sheet1",
"data": [
["Item", "Amount"],
["Rent", 900],
["Power", 75.5],
["Total", 975.5]
],
"columns": [
{ "width": 101.16, "title": "A", "type": "text", "hidden": false },
{ "width": 100, "title": "B", "type": "text", "hidden": false }
],
"rows": {},
"cells": {},
"style": { "A1": "text-align: left; pointer-events: none", "B2": "pointer-events: none" },
"mergeCells": {}
}
]
}Output for a small WK1 file in which B4 is a formula (its saved result, 975.5, is returned). style is trimmed to two cells.
Limitations
- Formulas are not decoded: you get the result Lotus saved, not the formula text.
- WK3, WK4 and .123 files return cell values, sheet names and column widths, but not number formats or cell styles; the .FM3 and .FMT formatting files are not read.
- WK1 labels are read as Latin-1, so the Lotus character set (LICS) is not translated. WK3 and newer text is decoded from LMBCS, except its double-byte Asian groups.
- Number formats are not applied, so dates come back as serial day numbers.
Frequently asked questions
Can TabularJS read .123 files from Lotus SmartSuite?
Yes. .123 files (1-2-3 97 and Millennium, part of SmartSuite) return their cell values, sheet names and notes, as do .wk3 and .wk4 files. Formulas come back as their saved results, and formatting is not read.
Why do I get numbers instead of formulas?
Lotus stores each formula as compiled tokens plus its last result. TabularJS returns the result and does not decode the tokens, so a formula cell holds its value.
How are Lotus dates returned?
As serial day numbers. Lotus 1-2-3 and Excel share the same 1900 date system, so you can convert them the same way you convert Excel serial dates.
What if the file has no extension?
TabularJS checks the first bytes for the Lotus beginning-of-file record and parses the file as WK1 when it finds it. You can also pass { extension: 'wk1' }.
Why TabularJS for Lotus 1-2-3?
- No external spreadsheet parser dependencies: faster installs, smaller bundles.
- One API in Node.js and modern browsers.
- Output is shape-compatible withJspreadsheet: render parsed data in a live workbook with one call.