Shellによるデバッグのテスト。
コメントで教えて頂いたものを使ってみました。
使用方法は以下の通り。
- まず一番上の「Shell」の上で右クリックして、「このリンクをブックマーク」でブックマークに追加。
- JavaScriptを動作させるページを開いて、さっき登録した「Shell」ブックマークを選択。するとコンソールが開く。
- scope( 変数 );で変数の型が分かる。
- props( 変数 );でメソッドとフィールドの一覧を取得できる。
というわけで、これを使って、XMLの中身を見てみました。
- サンプル:Shellによるデバッグのテスト。
まず、あらかじめ対象の変数をグローバル変数にもコピーするようにしておきます。
test.js
// デバッグ用。 var debugAjax = null; // ... function next( imageObjId, textObjId ) { // XMLHttpRequestを取得します。 var ajax = createXMLHttpRequest(); // デバッグ用の方にセットします。 debugAjax = ajax;
XMLの方はこう。
00000000.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <page> <image>a.jpg</image> <text>恋歌:デバッグってなに?</text> </page> </pages>
そうしたら、このページで一回[▽]をクリックしてから、ブックマークの「Shell」を選択、開いたウィンドウで次のように試してみました。
scope( debugAjax ); Scope is now [object XMLHttpRequest]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. scope( debugAjax .responseXML ); Scope is now [object XMLDocument]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. scope( debugAjax .responseXML.getElementsByTagName( "page" ) ); Scope is now [object HTMLCollection]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. scope( debugAjax .responseXML.getElementsByTagName( "page" )[0] ); Scope is now [object Element]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. debugPage = debugAjax .responseXML.getElementsByTagName( "page" )[0]; [object Element] scope( debugPage ); Scope is now [object Element]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. scope( debugPage.getElementsByTagName( "image" )[0] ); Scope is now [object Element]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. debugImage = debugPage.getElementsByTagName( "image" )[0]; [object Element] scope( debugImage ); Scope is now [object Element]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. scope( debugImage.childNodes ); Scope is now [object NodeList]. If a variable is not found in this scope, window will also be searched. New variables will still go on window. scope( debugImage.childNodes[0] ); Scope is now [object Text]. If a variable is not found in this scope, window will also be searched. New variables will still go on window.
これとDOMのリファレンスを比較。
前回は、debugImageから直接中身をなんで取れないのかと思ったけど、こういうことかな。
- まず「debugImage.childNodes[0]」とすることで<image>タグの「最初の子ノード」として<image>a.jpg</image>の「a.jpg」の所を取り出す。
- 取り出した「a.jpg」の所は、一応子ノードなのでNodeインターフェイス。
- でも実際にはText型で、Text型の場合にはnodeValueで該当する文字列を取得できる(リファレンスの「Interface Node」の表を参照)。
- なので、これで"a.jpg"という文字列が取得できる。
ということかな。
ようするに、<tag>AAAAA</tag>という場合に、"AAAAA"は「<tag>の値」として取り出さず、まずその子ノードとして取得して、それがText型だから文字列として取得する、という感じかな。
ややこしいけど、分かっちゃえばそんなでもないか。
XML1つに複数page。
前回は複数のXMLファイルを用意しましたが、今回は1ファイルにしました。
- サンプル:XML1つに複数page。
XMLファイルでは複数の<pages>タグ内の<page>タグを複数にしてあります。
00000000.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <page> <image>c.jpg</image> <text>恋歌:宿題がいっぱいだよぅ</text> </page> <page> <image>c.jpg</image> <text>風太:俺んちで一緒にやるか?</text> </page> <!-- 略 --> </pages>
getElementsByTagName( "page" )すると、<page>タグ全部を配列として取得できるので、これを上からベタに出力します。
test.js
// 「次に読み込むpage」を格納するグローバル変数。 var nextPage = 0; // ... // <page>を取得します。 var page = ajax.responseXML.documentElement.getElementsByTagName( "page" )[nextPage]; // ... // ページをインクリメントします。 ++nextPage; if( nextPage == ajax.responseXML.documentElement.getElementsByTagName( "page" ).length ) { nextPage = 0; }
とりあえずこれで1ファイルにまとまりました。
実際には、これと複数ファイルの両方に対応させて、さらに1ファイル内でも飛べるようにしたりとかしたりもできるようにしたいなと。
XMLを続けて読み込む。
XMLから「次に読み込むXML」を取ってくるようにしました。
- サンプル:XMLを続けて読み込む。
XMLファイルに<next>タグを追加して、それで「次のXMLファイル」を指定します。
00000000.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <page> <image>a.jpg</image> <text>恋歌:おはよー!</text> <next>00000001.xml</next> </page> </pages>
JavaScriptでは、「次のXML」を変数に取っておきます。
test.js
// 「次に読み込むXMLファイル」を格納するグローバル変数。 var nextXml = "00000000.xml" // ... // <next>の中身を取得します。 nextXml = page.getElementsByTagName( "next" )[0].childNodes[0].nodeValue;
こうすることで、「1ページ毎」の情報をXMLファイル単位で分けることができます。
ただ、これだとちょっと非効率な所もあるんで、せっかくXMLのタグを<pages>と<page>に分けてるんだから、複数の<page>タグが置けるようにするのもいいかも。
ファイル数多くなるとちょっときつい……。
IEとFireFoxでパーシングの仕方が違う!
FireFox対応版、解決編。
- XMLの各要素のアクセスにインデックスナンバーじゃなく文字列で指定したい。
実は、XMLの処理に関しても、FireFoxでは動かない所があって、結果的にこの処理をすることで解決したとゆー。
とりあえず、テスト用のサンプルを。
XMLファイルは以下のようになっています。
data.xml
<?xml version="1.0" encoding="UTF-8" ?> <pages> <page> <image>Do.jpg</image> <text>…………ちっちゃくないもん</text> </page> </pages>
このルートの要素数、つまり<pages>タグ内の要素数を取得します。
test.js
// ルートの要素数の取得。 var length = ajax.responseXML.documentElement.childNodes.length;
childNodesに「子ノード」が入っているので、その要素数をlengthで取得します。
<pages>タグの中には<page>タグしかないので、一見「1」になりそうですが、IEは「1」、FireFoxは「3」になります。
IEとFireFoxとでXMLHttpRequestで実装しているパーシング処理方法が違うらしく、FireFox版は「タグの間の空白やタブ」も数えちゃうみたいです。
この点について書いてあるところがありました。
ここを参考に、昨日のFireFox修正版では以下のようにしました。
test.js
// <page>を取得します。 var page = ajax.responseXML.documentElement.getElementsByTagName( "page" )[0]; // <image>の中身を取得します。 var imageUrl = page.getElementsByTagName( "image" )[0].childNodes[0].nodeValue; // イメージ置き換え先の取得。 var imageObj = document.getElementById( imageObjId ); // イメージを置き換えます。 imageObj.src = imageUrl;
話が前後しますが、要素をインデックスナンバーではなく文字列で取得するにはgetElementsByTagName()メソッドを使用します。
このメソッドでタグを直接指定できるので、空白やタブを取得することはありません。
このメソッドは、複数のタグが見つかった場合のために配列を返すので、[0]で最初のものだけ取得するようにします。
……ここまではいいんだが、正直、最後の「childNodes[0].nodeValue」はよくわからん(汗)。
型をちゃんと理解してないからっぽいなぁ。
次は「どれがどの型か」っていうのをちゃんとまとめることにします。
うはぁ、エロゲーからどんどん離れてく……。
オブジェクトの指定をIDで統一
FireFox対応版、解決編。
- <IMG NAME="char">と<DIV ID="maintext">で渡し方が違うので統一したい。
の解決編。
NAME属性の方で統一しようとしたんだけどうまくいかなかったんで、IDの方で統一しました。
<IMG>タグの方も、NAME属性ではなくID属性で名前を指定します。
それを、getData()メソッドに文字列として渡します。
index.html
<IMG ID="character" SRC="Ki.jpg" BORDER="0"><BR> <DIV ID="maintext"> </DIV><BR> <input type="button" value="「喜」へ切り替え" onClick="getData( 'dataKi.xml', 'character', 'maintext' ); return false;"> </form> <input type="button" value="「怒」へ切り替え" onClick="getData( 'dataDo.xml', 'character', 'maintext' ); return false;">
受け取ったメソッドではgetElementById()メソッドで名前から
オブジェクトを取得します。
test.js
// <image>の中身を取得します。 var imageUrl = page.getElementsByTagName( "image" )[0].childNodes[0].nodeValue; // イメージ置き換え先の取得。 var imageObj = document.getElementById( imageObjId ); // イメージを置き換えます。 imageObj.src = imageUrl; // <text>の中身を取得します。 var text = page.getElementsByTagName( "text" )[0].childNodes[0].nodeValue; // テキスト置き換え先の取得。 var textObj = document.getElementById( textObjId ); // テキストを置き換えます。 textObj.innerHTML = text;
これに対して値をセットします。
個人的には、逆にNAMEの方で統一したかったんだけど、<DIV>タグにNAME属性付けてそれで渡してもエラーになっちゃったんで……このあたりの完全な構文仕様書が欲しい……。