Traversing an HTML table with JavaScript and DOM Interfaces

Introduction

この文書では、強力で基本的な DOM レベル 1.0 のメソッドと、それを JavaScript からどのように使用するかざっと見ていきます。どのようにして HTML 要素を動的に生成、アクセス、制御、削除するかを学ぶことができます。ここで紹介する DOM メソッドは HTML に限ったものではなく、XML に対しても用いることができます。ここで用意しているデモは、Mozilla ブラウザ や他の Netscape の次世代 Navigator ブラウザ 【訳注: Netscape 6 のことを指しています】 のような Mozilla ベースブラウザなど、DOM レベル 1 を完全にサポートするブラウザであればどれでも正常に動作します。この文書のコードサンプルは IE5 でも動作します 【訳注: 現在では Opera や Safari なども含めほとんどのブラウザで DOM レベル 1 がサポートされています】

ここで紹介する DOM メソッドは ドキュメントオブジェクトモデル (コア) レベル 1 仕様の一部に過ぎません。 DOM レベル 1 には HTML ドキュメント特有のメソッド (DOM 1 HTML) と共に、一般的なドキュメントアクセスと操作 (DOM 1 コア) のためのメソッドが含まれています。

Sample1.html の概要

この文書はサンプルコードを通して DOM を紹介するものです。始めに、以下の HTML サンプル (sample1.html) から見ていきましょう。 HTML の table を動的に生成するために JavaScript から DOM レベル 1 メソッドを使用しています。このサンプルでは、各セルの中にテキスト内容がある 4 つのセルからなる小さな表を作っています。セルのテキスト内容は当該セルの表中での行と列を示す "セルは y 行 x 列 です" というものです。

<html>
<head>
<title>サンプルコード - 基本的 DOM インターフェイスによる HTML 要素の動的操作法</title>
<script>
    function start() {
        // get the reference for the body
        var body = document.getElementsByTagName("body")[0];

        // creates a <table> element and a <tbody> element
        var tbl     = document.createElement("table");
        var tblBody = document.createElement("tbody");

        // creating all cells
        for (var j = 0; j < 2; j++) {
            // creates a table row
            var row = document.createElement("tr");

            for (var i = 0; i < 2; i++) {
                // Create a <td> element and a text node, make the text
                // node the contents of the <td>, and put the <td> at
                // the end of the table row
                var cell = document.createElement("td");
                var cellText = document.createTextNode("セルは "+j+" 行 "+i+" 列 です");
                cell.appendChild(cellText);
                row.appendChild(cell);
            }

            // add the row to the end of the table body
            tblBody.appendChild(row);
        }

        // put the <tbody> in the <table>
        tbl.appendChild(tblBody);
        // appends <table> into <body>
        body.appendChild(tbl);
        // sets the border attribute of tbl to 2;
        tbl.setAttribute("border", "2");
    }
</script>
</head>
<body onload="start()">
</body>
</html>

要素とテキストノードを生成する順序を意識しながら確認していってください。

  1. まず、<table> 要素を生成します。
  2. 次に、<table> 要素の子供である <tbody> 要素を生成します。
  3. 次に、<tbody> 要素の子供である <tr> 要素を生成するループを使用します。
  4. 各 <tr> 要素に対して、その子供である <td> 要素を生成するループを使用します。
  5. そして各 <td> 要素に対して、表中セルのテキストと共にテキストノードを生成します。

まずは <table>、<tbody>、<tr>、<td> 要素、さらにテキストノードを生成し、それから逆の順番で各オブジェクトをその親に適用していきます。

  1. まず、各テキストノードをその親である <td> 要素へと次のようにして付加します
    cell.appendChild(cellText);
  2. 次に、各 <td> 要素をその親である <tr> 要素へと次のようにして付加します
    row.appendChild(cell);
  3. 次に、各 <tr> 要素をその親である <tbody> 要素へと次のようにして付加します
    tblBody.appendChild(row);
  4. 次に、<tbody> 要素をその親である <table> 要素へと次のようにして付加します
    tbl.appendChild(tblBody);
  5. 次に、<table> 要素をその親である <body> 要素へと次のようにして付加します
    body.appendChild(tbl);

この手法を覚えておきましょう。 W3C DOM によるプログラミングでは頻繁に使うことになります。まず、トップダウンで要素を作成し、子供を親へとボトムアップで付加していくのです。

JavaScript コードによって生成される HTML マークアップはこのようになります。

...
<table border="2">
<tr><td>セルは 0 行 0 列 です</td><td>セルは 0 行 1 列 です</td></tr>
<tr><td>セルは 1 行 0 列 です</td><td>セルは 1 行 1 列 です</td></tr>
</table>
...

このコードによって生成される TABLE 要素とその子要素を示す DOM オブジェクトツリーはこのようになります。

Image:sample1-tabledom.jpg

ほんの幾つかの DOM メソッドを使用するだけでこのように表と内部の子要素を構築できます。生成しようと計画している構造のツリーモデルを頭に置いておくことを忘れないようにしてください。そうすれば必要なコードを書くのは簡単です。図 1 の <table> ツリーでは <table> 要素は <tbody> 要素という子を 1 つ持ちます。<tbody> は 2 つ子を持ちます。各 <tbody> の子 (<tr>) は子を 1 つ (<td>) 持ちます。最後に各 <td> はテキストノードという子を 1 つ持ちます。

基本的 DOM メソッド - Sample2.html

getElementsByTagName は Document インターフェイス 及び Element インターフェイス両方のメソッドであり、従って全ての Element オブジェクトだけではなくルートドキュメントオブジェクトも getElementsByTagName メソッドを持っています。ある要素の子供リストをタグ名により選択して取得するには element.getElementsByTagName(tagname) が利用できます。

getElementsByTagName は指定されたタグ名を持つ子要素のリストを返します。返して欲しい項目番号のインデックスを渡して item メソッドを呼ぶことで、その子要素のリストから個別の要素を取り出すことができます。リストにある最初の子要素は 0 番目の要素となります。簡単でとても単純ですが、大きな構造が対象となる場合には注意が必要になります。次のトピックでは Table の例を続けて扱っていきますが、幾つか基本的なメソッドを紹介するためにより単純な例を示します。

<html>
<head>
<title>サンプルコード - 基本的 DOM インターフェイスによる HTML 要素の動的操作法</title>
<script>
    function start() {
        // body 要素全てのリストを取得します (あるのは 1 つだけですが)
        // それからその要素の 0 番目 (最初) の要素を選択します
        myBody = document.getElementsByTagName("body")[0];

        // 今度は body の子供である p 要素を全て取得します
        myBodyElements = myBody.getElementsByTagName("p");

        // p 要素のリストから 2 番目の項目を取得します
        myP = myBodyElements[1];
    }
</script>
</head>
<body onload="start()">
<p>hi</p>
<p>hello</p>
</body>
</html>

この例では、myP 変数を body 中の 2 つ目の p 要素を表す DOM オブジェクトに設定しています。

  1. まず、全ての body 要素リストをこのようにして取得します。
    myBody = document.getElementsByTagName("body")[0]
    全ての有効な HTML ドキュメントでは body 要素は 1 つしかないため、このリストは 1 項目だけを持ちます。つまり、[0] を使って、そのリストの最初の要素を選択することで取得できます。
  2. 次に、body の子供である全ての p 要素をこのようにして取得します。
    myBodyElements = myBody.getElementsByTagName("p");
  3. そして p 要素のリストから二つ目の項目をこのようにして取得します。
    myP = myBodyElements[1];

Image:sample2a2.jpg

一旦 HTML 要素に対応する DOM オブジェクトを取得すれば、そのプロパティを設定することできます。例えば、背景色のスタイルプロパティを設定したいのであればこのように加えるだけです。

myP.style.background = "rgb(255,0,0)";
// インラインの STYLE 属性を設定

document.createTextNode("..") によるテキストノードの生成

document オブジェクトを createTextNode メソッドを読んでテキストノードを生成するのに使用します。テキスト内容を渡す必要があるだけです。返り値はそのテキストノードを表すオブジェクトとなります。

myTextNode = document.createTextNode("world");

これはそのテキストデータが「world」である TEXT_NODE 型 (テキスト断片) 【訳注: TEXT_NODE はノードの型を表す定数の 1 つとして定義されていますが、厳密には型ではありません】 のノードを生成し、myTextNode がこのノードオブジェクトへの参照だということです。このテキストを HTML ページに挿入するには、このテキストノードを何か他のノード要素の子供にする必要があります。

appendChild(..) による要素の挿入

そこで myP.appendChild([ノード要素]) を使って、その要素を 2 つ目の <p> 要素の子供とします。

myP.appendChild(myTextNode);

例を見て頂いたところで、単語 hello と world が一緒になっていることに注目して下さい: helloworld。ご覧のように外見的には、HTML ページを見ると 2 つのテキスト hello と world は単一ノードのように見えますが、ドキュメントモデルでは 2つのノードがあるのです。 2つ目のノードは TEXT_NODE 型の新しいノードで、2つ目の <p> タグの 2つ目の子供です。以下の図はドキュメントツリー中につい先程生成された Text Node オブジェクトを表しています。

Image:sample2b2.jpg

hello と world の 2つの語の間に空白を付け加えるには createTextNode と appendChild を使うと簡単です。但し appendChild メソッドは丁度単語 world が 単語 hello の後に追加されたように子供を最後の子供の後に追加するものであり、Text ノードを hello と world の間に追加しようとするのであれば、appendChild ではなく insertBefore を使わなければならないことにも注意が必要です。

ドキュメントオブジェクトと createElement(..) メソッドによる新しい要素の生成

createElement によって HTML 要素やその他好きな要素を新しく生成できます。例えば、新しい <p> 要素を <body> 要素の子供として生成したければ、先の例では myBody を使用して新しい要素ノードを追加できます。新しいノードを生成するには単に document.createElement("タグ名") を呼びます。例を挙げると:

myNewPTAGnode = document.createElement("p");
myBody.appendChild(myNewPTAGnode);

Image:sample2c.jpg

removeChild(..) メソッドによるノードの削除

各ノードを削除することができます。次の行は myP (2 つ目の <p> 要素) の単語 world を含むテキストノードを削除します。

myP.removeChild(myTextNode);

最後に、先程生成した <p> 要素中に myTextNode (単語 world を含む) を追加する事ができます。

myNewPTAGnode.appendChild(myTextNode);

最終的に変更されたオブジェクトツリーはこのような状態なります:

Image:sample2d.jpg

テーブルの動的生成 (Sample1.html に戻って)

この文書ではこれ以降再び sample1.html を扱っていきます。以下の図はこの例で生成される table オブジェクトツリー構造を表しています。

HTML テーブル構造の再確認

Image:sample1-tabledom.jpg

要素ノードの生成とそのドキュメントツリーへの挿入

sample1.html に於ける基本的な table 生成の手順は:

  • body オブジェクトを取得する (document オブジェクトの最初の項目)。
  • 全ての要素を生成する。
  • 最後に、各子供を (上の図のように) table 構造に従って付加していきます。以下のソースコードは sample1.html のコメント付き版になります。


start 関数の最後には新たなコードがあります。 DOM のメソッド setAttribute を用いて table の border プロパティが設定されており、setAttribute は属性名と属性値という 2 つの引数を取ります。setAttribute メソッドを用いて任意の要素の任意の属性を設定することができます。
<head>
<title>サンプルコード - 基本的 DOM インターフェイスによる HTML 要素の動的操作法</title>
<script>
    function start() {
        // body への参照を取得します
        var mybody = document.getElementsByTagName("body")[0];

        // <table> と <tbody> 要素を生成します
        mytable     = document.createElement("table");
        mytablebody = document.createElement("tbody");

        // 全てのセルを生成します
        for(var j = 0; j < 2; j++) {
            // <tr> 要素を生成します
            mycurrent_row = document.createElement("tr");

            for(var i = 0; i < 2; i++) {
                // <td> 要素を生成します
                mycurrent_cell = document.createElement("td");
                // テキストノードを生成します
                currenttext = document.createTextNode("cell is row " + j + ", column " + i);
                // 生成したテキストノードを <td> セルへと付加します
                mycurrent_cell.appendChild(currenttext);
                // その <td> セルを <tr> 行へと付加します
                mycurrent_row.appendChild(mycurrent_cell);
            }
            // その <tr> 行を <tbody> へと付加します
            mytablebody.appendChild(mycurrent_row);
        }

        // <tbody> を <table> へと付加します
        mytable.appendChild(mytablebody);
        // <table> を <body> へと付加します
        mybody.appendChild(mytable);
        // mytable の border 属性を 2 に設定します
        mytable.setAttribute("border","2");
    }
</script>
</head>
<body onload="start()">
</body>
</html>

DOM と CSS によるテーブルの操作

テーブルからのテキスト取得

この例では 2つの新しい DOM 属性を紹介します。まず mycel の子ノードリストを取得するのに childNodes 属性を使用します。childNodes リストはその名前や型が何であるかにかかわらず全ての子ノードを含んでいます。getElementsByTagName のように、ノードのリストを返します。違いは getElementsByTagName が指定したタグ名の要素だけを返すということです。リストが返されれば、望みの子項目を検索するのに [x] メソッドを使用します。この例では table 2 行目 2 つ目のセルのテキストノードを myceltext に格納します。そして結果を表示するためにこの例では、myceltext のデータを内容とする新しいテキストノードを生成してそれを <body> 要素の子供として付加します。

オブジェクトがテキストノードである場合、data 属性を使用して当該ノードのテキスト内容を得ることができます。
mybody      = document.getElementsByTagName("body")[0];
mytable     = mybody.getElementsByTagName("table")[0];
mytablebody = mytable.getElementsByTagName("tbody")[0];
myrow       = mytablebody.getElementsByTagName("tr")[1];
mycel       = myrow.getElementsByTagName("td")[1];

// mycel の childNodes リスト中の最初の項目要素
myceltext=mycel.childNodes[0];

// currenttext の中身は myceltext の data 内容
currenttext=document.createTextNode(myceltext.data);
mybody.appendChild(currenttext);

属性値の取得

sample1 の最後に mytable オブジェクト上で setAttribute が呼び出されています。この呼び出しは table の border プロパティを設定するのに使用されています。属性を取得するには、属性オブジェクトを返す getAttribute メソッドを使います。属性の値を得るには、value プロパティを使用します:

mytable.getAttribute("border");

スタイルプロパティ変更による列の非表示化

JavaScript 変数にオブジェクトを納めさえすれば、スタイルプロパティを直接設定できます。以下のコードは 2 列目の各セル非表示とされ 1 行目の各セルが赤い背景色を持つように変更された sample1.html です。style プロパティが直接設定されていることに注意して下さい。

<html>
<body onload="start()">
</body>
<script>
    function start() {
       var mybody =document.getElementsByTagName("body")[0];
       mytable     = document.createElement("table");
       mytablebody = document.createElement("tbody");

       for(var j = 0; j < 2; j++) {
           mycurrent_row=document.createElement("tr");
           for(var i = 0; i < 2; i++) {
               mycurrent_cell = document.createElement("td");
               currenttext = document.createTextNode("cell is:" + i + j);
               mycurrent_cell.appendChild(currenttext);
               mycurrent_row.appendChild(mycurrent_cell);
               // 0 列目であればセルの背景色を設定し、
               // 1 列目であればセルを非表示とする
               if (i == 0) {
                   mycurrent_cell.style.background = "rgb(255,0,0)";
               } else {
                   mycurrent_cell.style.display = "none";
               }
           }
           mytablebody.appendChild(mycurrent_row);
       }
       mytable.appendChild(mytablebody);
       mybody.appendChild(mytable);
    }
</script>
</html>


Interwiki

Document Tags and Contributors

タグ:
Contributors to this page: Yoshino, Mgjbot
最終更新者: Yoshino,