- ベストアンサー
外部XMLのテキスト表示
WinXP、FLASH MX2004Proで編集しています。 FLASHで外部XMLを読み込んで、テキストを表示させたいと思っています。 XMLファイルはnews.xmlで、 -------------------- <?xml version="1.0" encoding="Shift_JIS" ?> <news> <item> <title>NEWSその1</title> <link>http://www.news01.com</link> </item> <item> <title>NEWSその1</title> <link>http://www.news02.com</link> </item> </news> </xml> -------------------- です。DWで作成したので、Shift-Jisで間違いないと思います。 FLASHでは、ステージ上にダイナミックテキストを配し、インスタンス名・変数名ともに「title_text」にしています。 また、フレームには以下のASを書いています。 -------------------- System.useCodepage = true; newsXML = new XML(); newsXML.load("news.xml"); newsXML.ignoreWhite = true; newsXML.onLoad = function(success) { total = newsXML.firstChild.childNodes.length; title_text.text = newsXML.firstChild.childNodes.firstChild.nodeValue; }; --------------------- 「NEWSその1」が表示されて欲しいところですが、実際には、 「undefind」 です。 ちなみに、 newsXML.onLoad = function(success) { if(success){trace("OK");}else{tarace("NG");} ・・・ としてみたら、「OK」が出力されました。 trace(total); では、「2」が出力されます(あってます)。 しかし、 trace(title_text); は、「undefind」です。 ぜひお力お貸しください。 お願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
ActionScript で扱う XML は、XML オブジェクトの中に作られた多くの変数で管理されます。 必要な情報を取り出すには、取り出したい情報を持つ変数のパスを正確に指定しなければなりません。 XML ファイルの読み込み自体は成功しても XML オブジェクトから情報を取り出すスクリプトに誤りがあると、null や undefined になってしまいます。 なお、ActionScript の XML は疑似的なものです。 いわゆるブラウザで使われる XML の規格から外れた書き方をしても上手くいったり、独特の構成で管理されたりと、少々ズボラなところがあります。 今回の問題点は、 > newsXML.firstChild.childNodes.firstChild.nodeValue; ↑この部分と思われます。 childNodes は子ノードの情報を管理している”配列変数”です。 子ノードが1つしかない場合でも childNodes は配列変数として確保されますので、中身を見る時は childNodes[ 0 ] というように、必ずインデックスを付けて指定します。 ちなみに undefined =未定義になるのは、配列変数 childNodes (配列変数なので Array クラス)には firstChild というプロパティが定義されていないためです。 firstChild を持っているのは childNodes に含まれる1つ1つの変数( childNodes[ 0 ] など)であって、childNodes そのものではありません。 この XML の構成ですと、各ノードの情報を持っている変数は ・ <news> ノード 最も外側の XML 宣言( <?xml … > )はノードと見なされないので、 <news> ノードが newsXML の最初の子になります。 従って、newsXML.firstChild または newsXML.childNodes[ 0 ] で参照できます。 ・ <item> ノード <news> ノードの子で、ご提示の例ですと2つあります。 つまり、newsXML.firstChild.childNodes[ 0 ] ~ [ 1 ] です。 ・ <title> と <link> ノード <item> ノードの子ですから、 newsXML.firstChild.childNodes[ n ].childnodes[ 0 ] ~ [ 1 ]です。 最初のインデックスの n は、 何番目の <item> ノードに属しているかによって違います。 となります。 それから、ActionScript では、ノードの値(タグで囲まれているテキスト)を取得する時には、そのノードの”最初の子の nodeValue ”で取得します。 例えば <item> ノードの子ノードである <title> の値を取得するには、” <title> ノードの最初の子ノード”の nodeValue を見ます。 まとめますと、例えば最初の <item> ノードにある <title> ノードの値を取得するスクリプトは newsXML.firstChild.childNodes[ 0 ].childNodes[ 0 ].firstChild.nodeValue このようになります。 --------------------------------------------------------------- XML オブジェクトには、childNodes という名前の配列変数で子ノードの情報が入っているほか、同じ階層に並んだ前後のノードや最初または最後の子ノードを参照するための情報・ノードの値など、様々な手がかりがたくさん記録されています。 どの手がかりを使って情報を取り出すかは、スクリプトを組む人の自由です。 配列変数であることを利用して childNodes[ n ] というように指定してもいいのですが、実際に値を利用する時に XML オブジェクトから直接取り出そうとすると、先述のようにパスが長くなってしまい、分かりにくくなる場合があります。 複雑な構成の XML やニュースの数が多い時は特に、Flash Player が解析してくれたものから必要な情報だけを取り出して、自分の配列変数に整理しておくと便利です。 今回の例では、1件のニュース= <item> ノードに、それぞれ2つの情報が含まれています。 管理の仕方は2次元配列でもいいのですが、[ 0 ] や [ 1 ] で表すと XML オブジェクトとあまり変わりませんから、配列変数に仕切り(フィールドといいます)を作ると分かりやすくなると思います。 例えば news_tbl という配列変数を用意し、これにフィールドを2つ(仮に news_title と news_link とします)作るとします。 news_title フィールドに <title> 、news_link フィールドに <link> の値を格納すると、例えば最初のニュースの情報を使いたい時は タイトル→ news_tbl[ 0 ].news_title リンク → news_tbl[ 0 ].news_link これだけのパスで済みます。 スクリプトにしますと、大体、次のようになります。 このスクリプトはフレームに設定してください。 (↓各行頭に全角のスペースが入っています。コピーする際は、全て半角のスペースかタブに置き換えてください) //ニュース情報を管理する配列変数 //フィールド news_title:タイトル news_link:リンクURL news_tbl = new Array(); //Shift-JISで読み込む System.useCodepage = true; newsXML = new XML(); newsXML.ignoreWhite = true; newsXML.onLoad = function( success ) { var i , total; var temp; var item_title , item_link; //ニュースの総数(=<item>ノードの数)を取得 total = newsXML.firstChild.childNodes.length; //解析用XMLオブジェクトの初期化 //先頭の<item>ノードを設定しておく temp = newsXML.firstChild.childNodes[ 0 ]; //<item>ノードの数だけ解析 for( i = 0 ; i < total ; i++ ) { //<item>ノードの2つの子ノードの値を取得 item_title = temp.childNodes[ 0 ].firstChild.nodeValue; item_link = temp.childNodes[ 1 ].firstChild.nodeValue; //取得した値を配列変数に格納 news_tbl[ i ] = { news_title : item_title , news_link : item_link }; //次の<item>ノードを探す temp = temp.nextSibling; } /*解析結果の確認*/ for( i = 0 ; i < news_tbl.length ; i++ ) { trace( ( i + 1 ) + "番目のニュース=" + news_tbl[ i ].news_title + " , " + news_tbl[ i ].news_link ); } }; //XMLファイルの読み込み newsXML.load("news.xml"); ************************************ newxtSibling は同じ階層に並んでいる次のノードを示す情報で、一種のリンクのようなものです。 今回の件では tempは <item> ノードを指しているので、これの nextSibling を辿って次の <item> ノードを参照できます。 <item> ノードから <title> と <link> ノードの情報を取得した後で temp の内容を nextSibling に書き換えておくと、<item> ノードを次々と指していくことができます。 この作業を for ループで <item> ノードの数だけ繰り返し、各ニュースの情報を配列変数に格納していきます。 今回は詳しく触れませんが。 テキストフィールドがこのスクリプトを書いたタイムラインにない場合などは、ターゲットパスの誤りにご注意ください。
その他の回答 (3)
- DPE
- ベストアンサー率85% (666/776)
JavaScript はあまり詳しくないので、一般的なことしかお答えできないのですが。 getURL に JavaScript を呼び出すスクリプトを書く時に、変数の部分もまとめて " " でくくると、変数の値が展開されないまま JavaScript に渡されてしまいます。 つまり、 window.open( 'link_text' , 'newwindow', … ); という JavaScript を呼び出しているのと同じ意味になります。 JavaScript を呼び出す際に getURL に指定するパラメータとは、JavaScriptに渡す引数も含めた、ひと続きの文字列です。 ActionScript にある変数の値を展開して渡すには、変数の前で一旦文字列を切り、変数を連結した後で残りの文字列を連結します。 「 " 」を含む文字列は \ でつないでおくと、「 " 」の部分で切られることなくひと続きの文字列にすることができます。 今回は” window.open( ”の後に link_text の値を連結しますので、getURL に渡す文字列の書き方としては "javascript:void(window.open( \"" + link_text + "\", \"newwindow\" , 'width=50,…,status=0'));" このような形になります。 「 " 」と「 ' 」が入り混じる文字列になりますが、さしあたって問題はないと思います。 getURL に渡す前に、仮に temp = "javascript:void(window.open( \"" + link_text + "\", \"newwindow\" , 'width=50,…'));"; というように適当な変数で文字列を作って、正確な文字列ができているか、特に link_text の値がきちんと連結されているかどうかを trace アクションで確認してみるといいでしょう。 ちなみに、ActionScript エディタでシンタックスに色を付ける設定にしていれば、getURL に渡すパラメータ部分の表示色も判断の材料になります。 正解は、” + link_text + ”の部分がテキスト、残りがストリングの色で表示されることです。 全部ストリングの色になっている場合は変数の値が展開されず、変数の名前が JavaScript に渡されてしまいます。 おかしな場所でテキストの色に変わったり \ だけがテキストの色になる時は、「 " 」「 ' 」「 \ 」の過不足・記述する順番の誤りが考えられます。 JavaScript を呼び出す作品は、HTML ファイルを作成して必ずブラウザで動作を確認してください。 スクリプトに問題がなくても、「ムービープレビュー」ではまず満足に機能しません。 新しいバージョンの Flash Player やブラウザ・OSのセキュリティ機能、閲覧者が使っているセキュリティソフト等により、JavaScript で開くポップアップウィンドウがブロックされてウィンドウが開かなかったり、Flash Player の方で設定が必要になることもあります。 JavaScript そのものや ActionScript との連携、セキュリティとの関連については、JavaScript のカテゴリーなどで別の質問を立ててみてください。詳しい方から回答が寄せられると思います。
お礼
お礼が遅くなって申し訳ありません。 そして重ね重ね、ありがとうございます。 + link_text + で引数を渡すことで、無事解決しました。 何度も丁寧に分かりやすく教えていただき、ほんとうにありがとうございました。大変助かりました。
- DPE
- ベストアンサー率85% (666/776)
#2です。 ステージにダイナミックテキストのテキストフィールド” title_text ”を作り、フレーム1に#2のスクリプトを書いて、newsXML.onLoad = function の中の配列変数 news_tbl に <title> と <link> ノードの情報を入れる処理の後に title_text.text = news_tbl[ 1 ].news_link; と入れてみましたが、undefined や空白にならず、ちゃんと表示できました。 trace アクションで確認できるのでしたら、配列変数 news_tbl にはとりあえず値が入っているということですから、原因は別のところにあるのだと思います。 まず、テキストフィールドのプロパティにある「変数:」の項目に何か変数名を指定している場合は、これを削除してください。 「変数:」の項目にインスタンス名と同じ名前を指定すると、名前の衝突が発生して不具合の原因になります。 まあ、今回のように onLoad イベントハンドラの中で text プロパティを書き換えるのであれば変数が指定されていても問題はないようですが、今回は変数名を指定する必要もありませんので。 それから、title_text.text に代入するスクリプトを、どの時点で実行していますでしょうか? 配列変数 news_tbl は最初は空っぽで、newsXML.onLoad = function で定義した関数が呼び出されるまで中身がありません。 この関数が呼び出されるのは XML が読み込まれた後で、news_tbl に中身が入るのもこの時です。 細かいことは省略しますが、例えば newsXML.onLoad = function( success ) { /*省略*/ }; newsXML.load( "news.xml" ); title_text.text = news_tbl[ 1 ].news_link; ↑このような順番でスクリプトを書くと、onLoad = function で定義された関数が呼び出される前に text プロパティに news_tbl[ 1 ].news_link の内容が代入されます。 この時点ではまだ配列変数の中身はありませんから、undefined になります。 また、for ループで表示する処理を同様の順番で行うと、news_tbl.length が 0 であるためにループが1度も実行されず、何も表示されない(” undefined ”の字も表示されない)ことになります。 XML を読み込むスクリプトを書いたフレームの1つか2つなど、すぐ先のフレームで news_tbl の値を使用するような場合も同じく、XML がまだ読み込まれておらず値の取得に失敗してしまう可能性があります。 ムービーの構成上、onLoad の中で text プロパティに代入できない事情があるのでしたら、一旦タイムラインを止めて onLoad = function の中でタイムラインを動かし、後のフレームで改めて代入する、といったフレーム構成にすると確実です。 例えば、フレーム2にテキストフィールド” title_text ”を配置し、フレーム1に XML の読み込みと解析のスクリプト、フレーム2に配列変数 news_tbl の内容をテキストフィールドに出力するスクリプトを書くものとします。 (さしあたって、title_text は4行程度の文章を表示できるよう、少々大きめに作成してください) この場合のスクリプトは、次のようになります。 一部は省略させていただきました。#2でご紹介しましたスクリプトと同じものを記述してください。 (↓各行頭に全角のスペースが入っています。コピーする際はご注意ください) ●フレーム1のスクリプト //ニュース情報を管理する配列変数 news_tbl = new Array(); //Shift-JISで読み込む System.useCodepage = true; newsXML = new XML(); newsXML.ignoreWhite = true; newsXML.onLoad = function( success ) { /*ここに、<title>と<link>の値を取得して news_tblに入れる処理を書く*/ //タイムラインを動かす play(); }; //XMLファイルの読み込み newsXML.load( "news.xml" ); //タイムラインを止めておく stop(); ●フレーム2のスクリプト //取得したニュースを表示 title_text.multiline = true; for( i = 0 ; i < news_tbl.length ; i++ ) { title_text.text += news_tbl[ i ].news_title + "\n"; title_text.text += news_tbl[ i ].news_link + "\n"; } //タイムラインを止めておく stop(); フレーム1で XML の読み込みの完了と news_tbl に値が設定されるまで待ち、準備が済んでからフレーム2に進むようにしています。 フレーム2以降であれば news_tbl に中身が入っていますので、undefined と表示されたり空白になることはないと思います。 *********************************** 「ムービープレビュー」で表示できるのにサーバーにアップしたら表示されなくなる場合は、XML ファイルを配置するフォルダに問題がありそうです。 swf ファイル・ HTML ファイルと同じフォルダに XML ファイルをアップしてみてください。 *********************************** あとは、インスタンス名やターゲットパスの誤り、何も表示されないとなると、背景と文字色が同じ色になっている・他の不透明オブジェクトが重なっていて見えなくなっている・・・などの些細な間違いくらいしか心当たりがないのですが。 onLoad = function の中で this や _parent を使った相対表現でターゲットパスを書く時は、this の指す対象の変化にご注意ください。 イベントハンドラにより呼び出される関数の中での this は、イベントハンドラの持ち主を指します。今回の例では XML オブジェクトの newsXML です。 どうしても相対表現を使う場合は、onLoad = function の外で //thisが指す対象を記憶 base_target = this; と変数に保護しておいて、onLoad = function の中では base_target.title_text ↑このような形でターゲットパスを書くと、_root からの絶対パスで書かなくても済みます。 ActionScript では、スクリプトを書く(関数など、実際に呼び出されるのはもっと後になるものを予め定義する場合も含みます)フレームで存在していないインスタンスや変数などを利用しようとすると、undefined 扱いになります。 テキストフィールド” title_text ”が持っている text プロパティを操作するなら、このスクリプトが記述されるフレームに title_text がステージに存在している必要があります。 スクリプトを書いたフレームよりも後で登場する予定のインスタンスや、既にステージを去ってしまったインスタンスに対して指示を出すことはできません。 たびたび長くなりましてすみませんでした。 この中に何かお役に立てるものがあれば、幸いです。
お礼
やはりご指摘いただいたとおり、title_text.text に代入するスクリプトを、どの時点で実行しているか、に問題がありました。 そしてなおかつ、「ムービーの構成上、onLoad の中で text プロパティに代入できない事情」がありまして、そのことについてとても丁寧に教えていただけたので、本当に感謝しています。 こんなにていねいに、わかりやすく、しかも二回も回答いただいて、ありがとうございました。 これからも教えていただいたことを参考に、がんばりたいと思います。
補足
本当に申し訳ないのですが、また疑問が出てきてしまいました。。 お時間ありましたらお願いします。 1フレーム目でXMLを読み込んだ後、2フレーム目で、<link>内のリンク先(質問文にはアドレスが書かれていますが、実際は“sample.html”などのファイル名です)を読み込んで、JavaScriptを利用して別窓に表示させたいのです。 2フレーム目のフレームに、 link_text.multiline = true; link_text = news_tbl[ i ].news_link; を追加しました。この時点でトレースすると、 link_text->sample.html news_tbl[ i ].news_link->sample.html で問題はありません。 しかし、いざボタンに、 on (release) { getURL("javascript:void(window.open(link_text, 'newwindow', 'width=50,height=50,scrollbars=0,resizable=0,status=0'));"); } としても別ウィンドウが開きません。 on (release) {内でトレースすると、 link_text->sample.html でした。 on (release) { getURL("javascript:void(window.open('sample.html', 'newwindow', 'width=50,height=50,scrollbars=0,resizable=0,status=0'));"); } とすると、開けます。 シングルクォーテーションの問題かと思い、 link_text = "'" + news_tbl[ i ].news_link + "'" ; として読み込んでみましたが、反応はありません。 本当に、お時間あったらでいいので、よろしくお願いします。
- himajin100000
- ベストアンサー率54% (1660/3060)
未検証。っていうか方法を知らない </xml> <!--何故か XML要素終了タグがある--> まぁ何故か読み込み成功しているので 単なる質問文の記述ミスとして無視する newsXML.firstChild.childNodes.firstChild.nodeValue; 疑問一つ目: childNodesの戻り値,つまり【nodeList】にfirstChildなんてあるのかな・・・? newsXML.firstChild.firstChildならともかく 疑問二つ目: W3Cの資料は見てないが, MDCの資料では http://developer.mozilla.org/en/docs/DOM:element.nodeValue を見る限り,その内容を返すのはElementノードではなくTextノード。 質問文からnewsXMLをdocumentElement(news要素)とすると newsXML news要素 .firstChild item要素 .firstChild title要素 .nodeValue; 要素のnodeValueなのでnull という気が。 >else{tarace("NG");} スペルミス。traceが正しい 一個でも当たってたらいいな。自信ないけど。
お礼
>何故か XML要素終了タグがある 読み込んでたXMLにも書かれていました。。でも読み込めてたんですね。もちろん修正しました。 >childNodesの戻り値,つまり【nodeList】にfirstChildなんてあるのかな・・・? >newsXML.firstChild.firstChildならともかく これでした。 実はのちのち newsXML.firstChild.childNodes[i].firstChild.nodeValue; で回そうと思っていたので、それをそのまま残して記述していたようです。つまりうっかりミス…すいません。 正しくは、 newsXML.firstChild.firstChild.firstChild.nodeValue; でした。 しかしこれで再び疑問が出てきました。。 ひとまず、ありがとうございました!
お礼
大変ていねいでわかりやすい回答、ありがとうございます。 今までこんがらがっていたことが、すっきりと整理されました。 とても勉強になりました。本当にありがとうございました。
補足
とても分かりやすい回答だったのですが、ひとつだけ、解決できないことがあります。 traceで確認できたデータを、いざダイナミックテキストの方へ代入しようとすると、またしてもundefindになってしまいます。 たとえば、 title_text.text = news_tbl[ 1 ].news_link; です。[ 1 ]の部分はiにして、forで回してもみましたが、表示されませんでした。 たびたび申し訳ありませんが、お時間ありましたらお願いします。