エレメントノードは複数の子ノードを持つこともあります。
.firstChildでは最初の子ノードしか得られません。.childNodesを使うと子ノードのリストが配列の形で得られます。
複数の子ノードを持つノード
<p id="nd11">複数の<em>子ノード</em>を持つノード</p>
k番目の子ノードの値を[ここがk番目]に変えるプログラムです。kに番号を入れて呼び出しています。(たとえば、onclick="ndtest11(2)" とか)
0 1 2 3
function ndtest11(k){
var koko = document.getElementById('nd11');
var childlist = koko.childNodes;
childlist[k].nodeValue = "[ここが" + k + "番目]";
}
子ノードは3つですが、番号は0から始まって [0],[1],[2] です。[3] はないので、反応しません(下図参照)。
[0],[2]のノードは[ここがk番目]にテキストが替わりますが、[1]のノードは替わりません。
その理由は、[0],[2]のノードはテキストノードで、[1]のノードはエレメントノードであるためです。
テキストノードの値はテキストですから変更できますが、エレメントノードの場合はさらにその子供のテキストノードを指定しなければ変更できません。

複数の子ノードを持つノード
<p id="nd12">複数の<em>子ノード</em>を持つノード</p>
kが1の時にはさらにその .firstChild の .nodeValue を[ここが1番目]に変えています。1以外では ndtest11 と同じです。やはりkに番号を入れて呼び出しています。(たとえば、onclick="ndtest12(1)" とか)
0 1 2
function ndtest12(k){
var koko = document.getElementById('nd12');
var childlist = koko.childNodes;
if (k==1) {
childlist[k].firstChild.nodeValue = "[ここが" + k + "番目(の子)]";
}else{
childlist[k].nodeValue = "[ここが" + k + "番目]";
}
}
次の例は全部のテキストがspanまたはemタグで囲まれていて、子ノードの数は3つです。
spanタグに挟まれemタグに挟まれまたspanタグに挟まれ
<p id="nd13">[0]<span>spanタグに挟まれ</span>[1]<em>emタグに挟まれ</em>[2]<span>またspanタグに挟まれ</span></p>
しかし、次の例では子ノードの数は7つあります。ただしブラウザによって解釈が異なります
spanタグに挟まれ emタグに挟まれ またspanタグに挟まれ
<p id="nd14">[0] [1]<span>spanタグに挟まれ</span>[2] [3]<em>emタグに挟まれ</em>[4] [5]<span>またspanタグに挟まれ</span>[6] </p>
0 1 2 3 4 5 6
function ndtest13(k){
var koko = document.getElementById('nd13');
var childlist = koko.childNodes;
if (childlist.length > k){
if (childlist[k].nodeValue==null) {
childlist[k].firstChild.nodeValue = "[ここが" + k + "番目(の子)]";
}else{
childlist[k].nodeValue = "[ここが" + k + "番目]";
}
}
var koko = document.getElementById('nd14');
var childlist = koko.childNodes;
if (childlist.length > k){
if (childlist[k].nodeValue==null) {
childlist[k].firstChild.nodeValue = "[ここが" + k + "番目(の子)]";
}else{
childlist[k].nodeValue = "[ここが" + k + "番目]";
}
}
}
配列の要素がいくつあるかは .length で調べます。
タグに囲まれていない所での改行(上の例では[0],[2],[4],[6])はテキストノードと解釈されていると考えると理解できます。
注意深く見ると文の途中の改行は空白と同じに解釈されているのがわかります。単語を空白文字で区切る西洋の言語ではこれが都合がよいのです。したがってこれも空白文字と同様にテキストと解釈し、ノードとするのは自然ということなのでしょう。
ただしブラウザによって解釈が異なります。インターネットエクスプローラでは改行だけのノードは無視され、後の例でも子ノードの数は3つになります。
閲覧者がどのブラウザで見にくるかわからない状態では子ノードの何番目かという決め方でプログラムするのは危険です。
.firstChildに対して.lastChildもあります。
子ノードの数と最後の子ノードを調べる方法があります。
<p id="nd15"><em>子ノードの数</em>と<em>最後の子ノード</em>を調べる方法があります。</p>
実行
function ndtest15(){
var elnd = document.getElementById('nd15');
var childlist =elnd.childNodes;
var z = childlist.length;
if (elnd.lastChild.nodeValue==null) {
var txt = elnd.lastChild.firstChild.nodeValue;
elnd.lastChild.firstChild.nodeValue = txt + "[" + z + "]";
}else{
var txt = elnd.lastChild.nodeValue;
elnd.lastChild.nodeValue = txt + "[" + z + "]";
}
}
.lastChild の代わりに 次のようにしてもできます。
function ndtest15(){
var elnd = document.getElementById('nd15');
var childlist =elnd.childNodes;
var z = childlist.length;
if (childlist[z-1].nodeValue==null) {
var txt = childlist[z-1].firstChild.nodeValue;
childlist[z-1].firstChild.nodeValue = txt + "[" + z + "]";
}else{
var txt = childlist[z-1].nodeValue;
childlist[z-1].nodeValue = txt + "[" + z + "]";
}
}
firstChildとlastChildを交換する仕掛け。
クリックした要素の子ノード数を最後のノードのテキストに追加する仕掛け。
index.htmlからは「始終交換」という名前のリンクから行けるようにすること。