最近、私はコードを書くとき、常に規格書を参考にしている。というのも、規格書が一次ソースであるからだ。参考書は二次、三次ソースである。規格書が間違っている可能性は、参考書よりも低いと考えられる。わざわざ間違っている可能性の高い参考書を参照したくはない。
しかし、ことWeb関連の規格に限っては、規格書は全く当てにならない。まして、HTML5は、現実の実装を元に規格を回ているのである。本来とは順番が違うのだ。
HTML5 li elementによると、ol要素の子であるli要素は、value属性を持ち、その値は、要素に対応するリスト番号であるという。
しかし、Chrome, Firefox, Opera, Safariは、このvalue属性をサポートしていなかった。IEはテストしていないので分からない。
この属性は、非常に便利だと思う。querySelectorなどで取得したli要素の番号を取得できるのだ。ところが、主要なブラウザはサポートしていないではないか。
あるいは、deprecatedな属性なのだろうか。しかし、HTML5の規格にある以上は、実装して欲しい。
幸い、今の私のドキュメントでは、CSSでリストの番号をいじるようなことはしていないので、親に対して、何番目のli要素であるかを調べるだけで足る。XHTML限定のコードは、以下の通り。
// calculate nth child element from parent node. function calculate_nth_li( element ) { var parent = element.parentNode ; var value = 0 ; for ( var i = 0 ; i != parent.childNodes.length ; ++i ) { var node = parent.childNodes.item( i ) ; if ( node.nodeType == node.ELEMENT_NODE && node.nodeName == "li" ) { ++value ; if ( element.isSameNode( node ) ) return value ; } } // shall not reach here. }
親に対して、何番目のノードの子であるかを取得する方法が、DOMで規定されていれば便利だろう、と思ったが、考えてみれば、ノードは、要素だけとは限らない。テキストとかコメントなどもある。現実的には、あまり役に立ちそうもない。
コメントで、Element Traversal SpecificationというすばらしいDOM規格があることを教えてもらった。さっそく、これを使って上記の関数を書き直した。
function nth_child_element( element ) { var n = 1 ; var iter = element.parentNode.firstElementChild ; while ( !iter.isSameNode( element ) ) { ++n ; iter = iter.nextElementSibling ; } return n ; }
コードを簡潔にするため、li要素かどうかの判定はなくした。なぜならば、規格準拠のXHTML5では、ol要素の直接の子は、かならずli要素でなければならないからだ。このコードは、私の書いたドキュメントにしか適用しない。そして私は、常に規格準拠のXHTMLを書くよう心がけているので、全く問題はない。
冷静に考えれば、Element Traversalと同等機能は、DOM level 2 coreを使って、自前で実装することもできる。しかし、このような単純なものは、標準にあった方がいい。
Element Traversal
ReplyDeletehttp://www.w3.org/TR/2008/WD-ElementTraversal-20080303/
を使うと少しきれいに書けると思います(仕様にはchildElements相当のAPIがないんですが、代わりに各ブラウザはchildrenを実装してます)。
また、XPathで自分より前の兄弟要素の数を調べれば、一発で調べることは可能ですね。XPath自体が面倒なので微妙なところですが。
おお、これはすばらしい。
ReplyDeleteW3C DOM Compatibility - Traversal
を見ても、最新の主要なブラウザは、すべて実装していますね。
親に対して何番目の子かという、そのものズバリの属性はないものの、これは使える。
XPathをXHTMLに対して適用しようとすると、名前空間との兼ね合いで、悲惨なことになります。
もう諦めました。
結局、世間もXPathなんて忘れて、querySelector相当のライブラリが乱立しましたからね。
querySelectorが規格化されたのも、むべなるかな。