0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HTMLの表をCSVにするとき colspan と rowspan で扱いを変えた

0
Posted at

背景

ウェブページの表をコピーして表計算ソフトに貼ると、たいてい崩れます。
私は昔からこれが苦手で、そのたびに手で直していました…。
というわけで、HTML の table を CSV にするだけのツールを作りました。

作っている途中で、結合セル(colspan / rowspan)の扱いをどうするかで手が止まりました。
その判断の話です。

用語

念のため。
colspan は「このセルを横に何マスぶん広げるか」の指定です。
rowspan は「縦に何行ぶん広げるか」の指定。
CSV は行と列がきれいな長方形に並んでいる前提の形式なので、結合セルはそのままでは表現できません。

colspan は補える

横方向は、実は素直です。
colspan="3" のセルがあったら、値を1つ入れて、残り2つは空文字を入れておけばよい。
列の位置が保たれるので、後続の列がずれません。

セルを取り出す部分は下記です。
table は DOMParser で読み込んだあとの table 要素、cellText() はセルから見えている文字だけを取り出す関数です。
out に「1行 = 文字列の配列」を詰めていきます。

function tableToRows(table){
  var out = [];
  var trs = table.querySelectorAll('tr');
  for(var i=0;i<trs.length;i++){
    var cells = trs[i].querySelectorAll('th,td');
    if(!cells.length){ continue; }
    var row = [];
    for(var j=0;j<cells.length;j++){
      var span = parseInt(cells[j].getAttribute('colspan') || '1', 10);
      if(!isFinite(span) || span < 1){ span = 1; }
      row.push(cellText(cells[j]));
      for(var k=1;k<span;k++){ row.push(''); }
    }
    out.push(row);
  }
  return out;
}

th と td を同じループで拾っているのは、見出し行も普通の行として1行目に置きたいからです。
CSV 側にヘッダー行という概念は無いので、区別する意味がありません。

rowspan は補えない

縦方向は、同じ手が使えません。
rowspan="2" のセルは1行目にしか存在しないので、2行目を処理している時点で「ここに1マス空ける」という情報が、その行の DOM のどこにも無いのです。
補うには、前の行で見た rowspan を覚えておいて、次の行の先頭に空セルを差し込む、という状態を持つ必要があります。

持てないわけではありません。
ただ、入れ子の table や不正な HTML が混ざると、この状態管理はすぐ壊れます。
壊れたときに何が起きるかというと、静かに1列ずれた CSV が出てきます。
「エラーにならず、間違った答えが出る」のがいちばん困る。

なので展開しないことにしました。
そのかわり、結果の横に行数と最大列数を出しています。

たとえば3行の表を入れて 最大列数: 3 と出れば、少なくとも列数は揃っています。
3 のはずが 2 と出たら、どこかで縦結合が効いている合図になります。
自動で直すのをやめて、ずれていることが目で分かる形にした、という判断です。

CSV の引用も少しだけ

ついでに。
セルにカンマが入っているときだけ、二重引用符で囲んでいます。

入力: <td>A4 コピー用紙, 500枚</td><td>480</td>
出力: "A4 コピー用紙, 500枚",480

囲む条件はカンマ・二重引用符・改行のどれかを含むときだけ。
全部囲んでも仕様上は正しいのですが、囲まないほうが目で読める CSV になるので、必要なときだけにしました。
TSV を選んだときは引用符を使わず、セル内のタブと改行を半角スペースに置き換えています。
タブ区切りは引用の仕組みを持たないので、区切り文字そのものを値から消すしかないためです。

置いてあるのはこちらです。
https://hashitosystem.com/tools/htmltablecsv/

自動で補正すると、補正できなかった場所が見えなくなる。
補えない側は、補わずに数字で見せるほうが結局速いと思います。


本記事はAI補助で執筆した、個人開発の紹介記事です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?