• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JavaScriptでHtmlのtable要素をCSVに変換する
#navi(../)
RIGHT:Posted by &author(aterai); at 2012-07-25
* JavaScriptでHtmlのtable要素をCSVに変換する [#r3f6b8d9]

#contents

** 概要 [#k7558714]
Html の table 要素を CSV に変換する Bookmarklet です。colspan、rowspan で結合するセルがある場合は、同文字列を挿入しています。

- ブックマークレットなどに登録して表のあるページで実行
- table要素をダブルクリックすると、tableがtextareaに置換されて、内容がCSVになりコピー可能
-- 子要素にtableが存在する場合は、ダブルクリックに反応しない
- textareaをダブルクリックすると、元のtableに戻る
- <thead><tfoot>は気にしていない(例えば、tbodyの前にあるtfootが、そのまま先の行としてCSVになる)
- <capthion>は無視
- <colgroup>のspan属性には未対応

**ソースコード [#sc8e81f4]
#code{{
// ==UserScript==
// @name        <table> to CSV
// @namespace   http://terai.xrea.jp/
// @include     http://*
// @description Html table -> CSV(textarea)
// @version     1.0.2
// ==/UserScript==
(function() {
  function table2csv(table) {
    var tr = table.getElementsByTagName("tr"),
    csv = "",i,j,k,l,xoff, text, csvRow, cells, td, array = [], lenr = tr.length, lenc;
    for(i=0; i<lenr; i++) {
      //前行のセルのcolspanで、すでにこの行は初期化されている場合がある
      if(array[i] == null) array[i] = [];
      cells = tr.item(i).cells;
      lenc = cells.length;
      for (j=0; j<lenc; j++) {
        td = cells.item(j);
        //タグの削除、タブをスペースに置換、両側trim、ダブルクオートの二重化
        text = td.innerHTML.replace(/<.*?>/mg, "").replace(/\t/g," ").replace(/(^\s+)|(\s+$)/g, "").replace(/\"/, '""');
        //前の行のrowspanですでにこのセルが使用されている場合はxoffだけ移動
        xoff = 0;
        while(array[i][j+xoff] != null) {
          xoff++;
        }
        for(k=0; k<td.colSpan; k++) {
          array[i][j+xoff+k] = text;
          for(l=0; l<td.rowSpan; l++) {
            if(array[i+l] == null) array[i+l] = [];
            array[i+l][j+xoff+k] = text;
          }
        }
      }
    }
    lenr = array.length;
    lenc = array[0].length;
    for(k=0; k<lenr; k++) {
      csvRow = "";
      for(l=0; l<lenc; l++) {
        //内容をダブルクオートで囲んでタブ区切りで追加
        csvRow += "\t\""+array[k][l]+"\"";
      }
      if(csvRow != "") {
        csvRow = csvRow.substring(1,csvRow.length);
      }
      csv += csvRow+"\n";
    }
    return csv;
  }
  var listener = function(e) {
    var tx = document.createElement("textarea");
    tx.value = table2csv(this);
    //textareaのサイズは適当
    tx.style.width  = '80%';
    tx.style.height = "240px";
    tx.originalTable  = this;
    this.tx = tx;
    this.parentNode.replaceChild(this.tx, this);
    tx.addEventListener("dblclick", function(e) {
      this.parentNode.replaceChild(this.originalTable, this);
    }, false);
  },
  table = document.getElementsByTagName("table"), i = 0, len = table.length;
  for(; i<len; i++) {
    //tableがネストしている(子tableが存在する)場合は、クリックしても無視する
    if(table[i].getElementsByTagName("table").length>0) continue;
    table[i].addEventListener("dblclick", listener, false);
  }
}());
}}

** Bookmarklet [#ab91c304]
- 名前(任意)
-- table2csv
- アドレス(YUI Compressor で圧縮)
 javascript:(function(){function e(x){var t=x.getElementsByTagName("tr"),o="",p,n,m,h,v,u,s,w,g,r=[],q=t.length,f;for(p=0;p<q;p++){if(r[p]==null){r[p]=[]}w=t.item(p).cells;f=w.length;for(n=0;n<f;n++){g=w.item(n);u=g.innerHTML.replace(/<.*?>/mg,"").replace(/\t/g," ").replace(/(^\s+)|(\s+$)/g,"").replace(/\"/,'""');v=0;while(r[p][n+v]!=null){v++}for(m=0;m<g.colSpan;m++){r[p][n+v+m]=u;for(h=0;h<g.rowSpan;h++){if(r[p+h]==null){r[p+h]=[]}r[p+h][n+v+m]=u}}}}q=r.length;f=r[0].length;for(m=0;m<q;m++){s="";for(h=0;h<f;h++){s+='\t"'+r[m][h]+'"'}if(s!=""){s=s.substring(1,s.length)}o+=s+"\n"}return o}var d=function(g){var f=document.createElement("textarea");f.value=e(this);f.style.width="80%";f.style.height="240px";f.originalTable=this;this.tx=f;this.parentNode.replaceChild(this.tx,this);f.addEventListener("dblclick",function(h){this.parentNode.replaceChild(this.originalTable,this)},false)},c=document.getElementsByTagName("table"),b=0,a=c.length;for(;b<a;b++){if(c[b].getElementsByTagName("table").length>0){continue}c[b].addEventListener("dblclick",d,false)}}());

- アドレス(テスト用に[http://terai.xrea.jp/data/javascript/table2csv.js table2csv.js]を読み込む)
 javascript:(function(){var s=document.createElement("script");s.charset="UTF-8";s.src="http://terai.xrea.jp/data/javascript/table2csv.min.js?"+(new Date()).getTime();document.body.appendChild(s)}());

** テスト用table [#tab5af2e]

- rowspan, colspan
|CENTER:100|CENTER:100|CENTER:100|CENTER:100|c
|A|B|C|D|h
|1|2|>|3|
|4|>|5|6|
|7|~|~|~|

- footer
||ファイル数|サイズ|総行数|コメント行|実行数|空行数|コメント率|h
|~合計|169|5291916|174370|77045|84804|12521||
|~平均||31313|1031|455|501|74|44.13%|
||||||||BGCOLOR(white):|c
|>|>|>|>|>|>|>|CENTER:footer|f

** 参考リンク [#dc357958]
- [http://marklets.com/CSV+from+HTML+tables.aspx CSV from HTML tables Bookmarklet | Bookmarklet Search Engine]
- [http://www.codekeep.net/snippets/ec9f4704-b88a-486a-98f9-896de6afb021.aspx CodeKeep Snippet : Convert html table to csv (JavaScript)]

** コメント [#pfe243fb]
- 表計算ソフトなどの場合は、Htmlのまま貼り付けるとspanに対応しているのでこのスクリプトは意味がない。自分の使いたいソフトには、Htmlのtable取り込み機能がなく、csvを読み込んで表にする機能と、連続する同文字列セルの結合があるので作成。取り込み作業は終わったので、もう必要ないけど、せっかくなので公開。 -- [[aterai]] &new{2012-07-24 (火) 17:59:18};
- 表計算ソフトなどの場合は、tableタグをコピペするだけでspanを考慮した表の取込みが出来るので、このスクリプトを使って CSV, TSV に変換して読み込む意味はあまりないかも。ただ、自分の使いたいソフトには、Htmlでのtable取り込み機能がなく、csvを読み込んで表にする機能と、連続する同文字列セルの結合が可能なので作成してみました。取り込み作業は終わったのでもう必要ないけど、せっかくなので公開しておきます。 -- [[aterai]] &new{2012-07-24 (火) 17:59:18};
- innerTextではなく innerHTML.replace(/<.*?>/mg, "") を使用して、FireFoxでも動作するように修正。 -- [[aterai]] &new{2012-07-27 (金) 14:49:37};

#comment