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