All formats

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

Data values
Formulas
Styles
Merged cells
Comments
Column metadata

Formula cells return the value Lotus saved with them; the formula itself is not decoded.

What TabularJS extracts from WKS files

Convert WKS to JSON in Node.js

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

js
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

json
{
  "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

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?