SheetJSで空の先頭行がデータ範囲に含まれる
要約
- SheetJSでExcelを読み取ったとき、空の先頭行がデータ範囲に含まれることがある
- 原因は、空行に見えても内部的なデータが残っているため
- 解決方法(2種類)
- Excel自体から先頭の空行を削除する
- データ範囲を検証し、正しくなければ先頭行を削除する
問題点:空の先頭行がデータ範囲に含まれる
Excelの読み込みを行うシステムでは、あらかじめ決まっているテンプレートに沿ってデータが記載されていることがよくあると思います。
そしてテンプレートによっては、シートの1行目に何も入力せず、余白として使用する場合があります。
このケースでは、常に2行目以降をデータ範囲として扱う必要が出てきます。
SheetJSは、基本的にデータの存在しない行列をデータ範囲外として扱います。特別なオプションや処理を追加する必要はありません。
しかし、データが存在しないように見えても内部的に残っている場合、対象行はデータ範囲に含まれてしまいます。
空の先頭行がデータ範囲に含まれているシートを取得し、JSONに変換しました。

const sheetName = workbook.SheetNames[0];
const sheet = workbook.Sheets[sheetName];
const jsonData = XLSX.utils.sheet_to_json(sheet);
出力内容は下記のようになり、空白セルがヘッダーとして扱われています。(__EMPTYは空白ヘッダーの代替文字列)
[
{
"__EMPTY_1": "項目1",
"__EMPTY_2": "項目2",
"__EMPTY_3": "項目3"
},
{
"__EMPTY_1": "データ1_項目1",
"__EMPTY_2": "データ1_項目2",
"__EMPTY_3": "データ1_項目3"
},
{
"__EMPTY_1": "データ2_項目1",
// ...
}
]
内部的なデータは、Excelセルを編集したときに残ることがあります。
このため、Excelを手動編集してからシステムで読み込む場合は、空の先頭行がデータ範囲に含まれるケースと含まれないケースの考慮が必要となります。
解決方法
1. Excel自体から先頭の空行を削除する
Excel側を変更できるのであれば、先頭行から空行を削除することが最も簡単な解決方法です。
ただ、システムの都合上変更が困難な場合もありますので、その場合は次に示すとおりデータ整形で対応していきます。
2. データ範囲を検証し、正しくなければ先頭行を削除する
ファイル読み込み後、対象シートのデータ範囲を検証することができます。
下記のコードでは、Excelの1枚目のシートを取得しています。
const sheetName = workbook.SheetNames[0];
const sheet = workbook.Sheets[sheetName];
sheetの中身は次のようになっています。
{
!ref: "A1:K4",
B2: {
h: "項目1",
// ...
},
B3: // ...
}
!refがシートのデータ範囲です。ここではA1が開始セルとなっています、しかし実際にはA1の値は取得されておらず、B2のデータから始まっており、空の先頭行がデータ範囲に含まれていることが分かります。
次のコードは、!refの値を検証してシートから先頭行を削除しています。
const sheetName = workbook.SheetNames[0];
const sheet = workbook.Sheets[sheetName];
if (sheet["!ref"] && sheet["!ref"].startsWith("A1")) {
const range = XLSX.utils.decode_range(sheet["!ref"]);
range.s.r += 1;
sheet["!ref"] = XLSX.utils.encode_range(range);
}
decode_rangeとencode_rangeはデータ範囲の変換ユーティリティです。
range.s.rはデータ範囲開始セルの行番号を示しており、1を加算することで先頭行をデータ範囲から除外しています。
また、変換時に範囲を指定して先頭行を削除することもできます。
const jsonData = XLSX.utils.sheet_to_json<FileJson>(sheet, {
range:
sheet["!ref"] && sheet["!ref"].startsWith("A1") ? 1 : undefined,
});
ファイル読み取り時の除外はできなかった
試した限りでは、ファイルの読み取り時に先頭の空白行をデータ範囲から除外することはできませんでした。
.xlsxや.xlsは自身のデータ範囲を保持しており、SheetJSはデフォルトでその値に従って読み込みを行います。
nodimオプションを付与することで、SheetJS側でデータ範囲を再検証できるそうですが、今回のパターンでは指定してもデータ範囲の変化はありませんでした。
const workbook = XLSX.read(binaryStr, { nodim: true });
参考
NCDC株式会社( ncdc.co.jp/ )のテックブログです。 主にエンジニアチームのメンバーが投稿します。 募集中のエンジニアのポジションや、採用している技術スタックの紹介などはこちら( github.com/ncdcdev/recruitment )をご覧ください!
Discussion