excel_plus v2.15.0
pub.dev GitHub

Excel to JSON

Read a spreadsheet as header-keyed maps, or serialise it straight to a JSON string.

Install#

dart pub add excel_plus
import 'package:excel_plus/excel_plus.dart';

A sheet as a list of maps#

The first row supplies the keys, and every row after it becomes one map. This is usually what you want when the spreadsheet is feeding a model constructor or an API call.

final excel = Excel.decodeBytes(File('people.xlsx').readAsBytesSync());

for (final row in excel['People'].rowsAsMaps()) {
  print('${row['name']} is ${row['age']}');
}
// {name: Alice, age: 30, active: true}
// {name: Bob,   age: 25, active: false}

A sheet as a JSON string#

final json = excel['People'].toJson();
// [{"name":"Alice","age":30,"active":true},{"name":"Bob","age":25,"active":false}]

final readable = excel['People'].toJson(pretty: true);

The whole workbook#

Without a sheet name you get every worksheet, keyed by name and in worksheet order.

final all = excel.toJson();
// {"People":[{"name":"Alice"}],"Totals":[{"sum":42}]}

final one = excel.toJson(sheet: 'People');

Choosing the header row#

Many real exports carry a title or a blank line before the real header. Point headerRow at the row you want, or pass null for an array of arrays with no header at all.

final later = sheet.toJson(headerRow: 2);    // skip a two line preamble
final grid  = sheet.toJson(headerRow: null); // [["name","age"],["Alice",30]]

How values are exported#

Numbers and booleans keep their Dart types. Dates and times become ISO 8601 strings, because JSON has no date type.

CellJSON
Text"Alice"
Int, Double30, 1.5
Booltrue
Date"2024-01-31"
DateTime"2024-01-31T09:30:00"
Time"09:30:00"
Formulaits cached result, or "=SUM(A1:A9)"
Error"#DIV/0!"
Emptynull

Pass formulasAsText: true to export formula text instead of cached results.

Messy headers#

Every map holds a key for each column in the sheet's used width, so all rows share the same keys and a blank cell reads as null. An empty header cell falls back to its column letter, and a repeated name gets a _2 suffix, so a column is never silently dropped. Rows where every cell is empty are skipped unless you pass skipEmptyRows: false.