- ベストアンサー
HTML文書の子要素と孫要素の表現方法について
- HTML文書の子要素とその子孫要素を表現する方法を調査しています。
- document.getElementsByTagName('*')の値をインデックスに変換して、子要素と孫要素を抽出する方法を求めています。
- 途中まで作成したコードが正しく動作しなかったため、説明の補足資料を提供しています。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
#2です。 基本的にDOMの通りでよいのであれば、#1にも書きましたように、子要素を処理する関数と子孫要素を処理する関数を作成しておいて、前者をループで呼び出せばよいと思われますので、再帰は不要かと思います。 >~だということでお願いします。 >例を、このようにして下さい。 って、なんだか作れと言われているような・・・ 作る気はなかったのですが、現在ある記述スタイルのお勉強を始めたところなので、お勉強のためにそのスタイルで… とは言っても、先週から始めたばかりなので少々中途半端なのと要領も悪そう。(一応、動作すると思います) * ご提示のHTMLのうちlink要素をmetaとscriptに変えています。 * 結果の確認のため、要素名と"undefinde"(文字列)でリスト化しています。 * 要素→要素名はtranslate内で行なっていますので、インデックスへの変換をするならここを修正。 * mapが使えない場合は展開してください。(実は、私の環境でも使えないんですけれど) (半角空白は全角に) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="ja"> <title>Example</title> <meta http-equiv="Content-Script-Type" content="text/javascript"> <script type="text/javascript"> <!-- window.onload = function(){ var stocker = function(){ this.stock = []; } stocker.prototype = { next : function(){ return this.stock.length; }, add : function(item){ this.stock[this.next()] = item; } } var nodeFilter = function(node){ return node?(node.nodeType==1):false; } var setNode = function(_, i){ return this[i]; } var translate = function(node){ return node?node.nodeName:"undefined"; // ←文字列のundefinedを使用。 } var setList = function(nodeList){ return new Array(nodeList.length).join().split(",") .map(setNode, nodeList).filter(nodeFilter); } var makeList = function(node, tag){ return setList(node.getElementsByTagName(tag)); } var listDescendant = function(node){ var descendants = makeList(node, "*"); this.add( translate(node) ); if(descendants.length) this.add(descendants.map(translate)); } var listChild = function(node){ var children = setList(node.childNodes); if(children.length){ var list = new stocker(); children.map(listDescendant, list); this.add(list.stock); } else { this.add(translate(null)); } } var html = makeList(document, "html")[0]; var list = new stocker(); listChild.call(list, html); makeList(html, "*").map(listChild, list); var result = list.stock; } //--> </script> </head> <body> <h1> <a href="/">Header</a> </h1> <ul id="nav"> <li> <a href="one/">One</a> </li> <li> <a href="two/">Two</a> </li> </ul> </body> </html> <実行結果> [ [HEAD,[TITLE,META,SCRIPT],BODY,[H1,A,UL,LI,A,LI,A]], [TITLE,META,SCRIPT], undefined, undefined, undefined, [H1,[A],UL,[LI,A,LI,A]], [A], undefined, [LI,[A],LI,[A]], [A], undefined, [A], undefined ]
その他の回答 (2)
- fujillin
- ベストアンサー率61% (1594/2576)
#1です。 >今の所は、<p>~</p>までが、p要素だということでお願いします その解釈にするなら、DOMを解析しても欲しい結果は得られないと思います。 #1にも書きましたように独自のパーサーを作るようなことになりますし、それはあくまでもHTMLソースの解析になってしまうのではないでしょうか。 DOMを解析してDOMと異なる結果を作り出すのは、大変難しいと思われます。 また、ご質問とは関係ありませんが、何にお使いになるのかわかりませんが、事前に解析しておいてもDOM要素は変更されるので、(特に)インデックス化してしまうとまったく使い物にならなくなる可能性が…
補足
http://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Html-source-code3.png では、Wikipediaより…… <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Example</title> <link href="screen.css" rel="stylesheet" type="text/css"> </head> <body> <h1> <a href="/">Header</a> </h1> <ul id="nav"> <li> <a href="one/">One</a> </li> <li> <a href="two/">Two</a> </li> </ul> </body> </html> 要素リスト[html,head,title,link,body,h1,a(1),ul,li(1),a(2),li(2),a(3)] (便宜上、順に数字) 構造リスト[[head,[title,link],body,[h1,a(1),ul,li(1),a(2),li(2),a(3)]],[title,link],undefined,undefined,[h1,[a(1)],ul,[li(1),a(2),li(2),a(3)]],[a(1)],undefined,[li(1),[a(2)],li(2),[a(3)]],[a(1)],undefined,[a(2)],undefined] 例を、このようにして下さい。 >また、ご質問とは関係ありませんが、何にお使いになるのかわかりませんが、事前に解析しておいてもDOM要素は変更されるので、(特に)インデックス化してしまうとまったく使い物にならなくなる可能性が… インデックス化した直後に使うので、問題ありません。 大きな関数の一部分として使うのみです。
- fujillin
- ベストアンサー率61% (1594/2576)
よくわかってませんが… 普通にDOMのツリー構造を記述するのではないですよね? 親要素に対して、 「子要素 + 孫以下の子孫要素の列挙」をペアにして列挙するのかと思いきや >[title],undefined,[p,[div1,div2,font],div3],[div1,div2・・・ あたりからよくわからなくなってくる。 ([title]が単独だし、div3の後にundefinedがないし・・・) 何となくの感想としては、ツリー構造を追いかけるわけではないので再帰の必要もなく、順にループ処理すればよいのでは? それよりも、そもそもとして >何かしら問題があっても、気にしないでください とはいうものの、ご提示のDOM構造を解析して、 >[html,head,title,body,p,div1,div2,font,div3] と認識するのにはかなり無理がありそう。 ご提示のような解析にしたければ、innerHTMLをとって独自にパーサーを作らないとならないのでは? (DOMで getElementsByTagName("*") を実際に取って確認してみてください)
補足
失礼しました。 確認しました。 http://www.eonet.ne.jp/~nga/html/div&p.html 今の所は、<p>~</p>までが、p要素だということでお願いします。 div3の後にundefinedが無いというのは、[div3,[undefined]]のようになっていないという話でしょうか。 もしそうであれば、[undefined]はナシということになっています。 「~.childNodesがなかったり」、「あっても、nodeType==1のものがなければ」、[undefined]は追加しない事、となっています。 説明不足ですみません。 >[title]が単独 要素リスト:[html,head,title,body,p,div1,div2,font,div3] 構造リスト:[[head,[title],body,[p,div1,div2,font,div3]],[title],undefined,[p,[div1,div2,font],div3],[div1,div2,[font]],undefined,[font],undefined,undefined] headの子要素は、titleだけなので、[title]という風に、単独です。 もし、headの子要素が、meta1,title,meta2なら、 [meta1,title,meta2]になります。 次のundefinedは、titleに子要素が無いからです。 要素リストのインデックスと、構造リストのインデックスは、ピッタリです。
お礼
本当にありがとうございます。 その様な方法があるとは、思いつきませんでした。 以下のようにして、使いたいと思います。 if((document.head||document.getElementsByTagName('head')[0]).children){ window.get=function(){ var index=0,structure=[],all=document.getElementsByTagName("*"),memo,children,array,index2,length=all.length,array2,j,k,i=0; for(var length2,length3;i<length;i++){ memo=++index; array=[]; index2=0; length2=(children=all[i].children).length; for(j=0;j<length2;j++){ if(array[index2++]=index++,length3=children[j].getElementsByTagName("*").length){ array2=Array(length3); for(k=0;length3--;){ array2[k++]=index++; } array[index2++]=array2; } } structure[i]=index2?array:0; index=memo; } return structure; }; } else{ window.get=function(){ var index=0,structure=[],all=document.getElementsByTagName("*"),memo,childNodes,array,index2,length=all.length,array2,j,k,i=0; for(var length2,length3;i<length;i++){ memo=++index; array=[]; index2=0; length2=(childNodes=all[i].childNodes).length; for(j=0;j<length2;j++){ if(1==(array2=childNodes[j]).nodeType && (array[index2++]=index++,length3=array2.getElementsByTagName("*").length)){ array2=Array(length3); for(k=0;length3--;){ array2[k++]=index++; } array[index2++]=array2; } } structure[i]=index2?array:0; index=memo; } return structure; }; }