CrossOverで天気予報API

アップフロンティア株式会社様のwidgetownでこのサイトで公開しているCrossOverライブラリが紹介されています。

第7回 天気予報APIを活用して、快適な秋を過ごそう!【特集 サンデープログラミング】|widgetown.

ご紹介の記事では、widgetownが財団法人日本気象協会と共同で提供している「天気予報API」を使用した天気予報や指標情報を表示するためのウィジェットのサンプルについて解説しています。

CrossOverライブラリはFlashのデータ保持領域にXMLのデータを取り込んで、JavaScriptにデータを渡すことができます。読み込む のは天気情報と洗濯情報の2つのXMLなのですが、提供されているライブラリでは1度に1つのデータ保持領域を作成するため、1つのXMLしか読み込むこ とができませんでした。そこで、CrossOver.jsを改良して、1度に複数のデータ保持領域を作成し、それぞれJavaScriptにデータを渡す ようにしました。

ほほー、なるほど。

たしかに、紹介されているソースを拝見すると複数のXMLも扱えるようです。

アップフロンティアのクロサキ様、すばらしい情報をどうもありがとうございます。

prototype.jsと連想配列

Ajaxアプリケーションの開発においてprototype.jsを使用すると様々な恩恵をえられる。

私自身も話題のJQueryよりもPrototype.jsを使用する機会の方が多いのだが、よく言われるように、配列やオブジェクトの汚染にも悩まされることが多い。

prototype.jsを使用していない場合の配列、連想配列、オブジェクトの初期化

prototype.jsを使用していない場合は、以下のように初期化することが一般的である。

var array = new Array(); // 配列の初期化
var hash = new Array(); // 連想配列の初期化
var obj = new Object(); // オブジェクトの初期化

prototype.jsを使用していない場合この方法で何も問題は生じないが、prototype.jsを使用するとループで処理した際などに意図していない値が出力されてしまうことがある。

これが、よくいわれるprototype.jsによる汚染である。

prototype.jsを使用した場合の初期化

上記のような汚染を免れる場合には以下のように初期化する必要がある。

var array = []; // 配列の初期化
var hash = {}; // 連想配列の初期化
var obj = {}; // オブジェクトの初期化

上記の例で注意する必要があるのは、連想配列である。

通常の場合、連想配列は配列と同じようにnew Array()とすればよいので、prototype.jsを使用する場合でも、hash = [];としてしまいがちだが、この方法では実際には汚染されてしまうので注意。

JavaScriptでは、連想配列とオブジェクトは同じ扱いであり、たとえばfoo.barという値にはfoo[bar]という方法でもアクセスできる。

そんなわけで、prototype.jsを使用する場合には、連想配列もオブジェクトとして初期化する必要がある。

ちなみに連想配列またはオブジェクトをループで処理する場合は以下のような感じ

for (var i in hash) {
  alert(hash[i]);
}

簡単なサンプルなので分かりにくいかもしれないが、iにはプロパティ名(連想配列で言えばキー)が、hash[i]には値が格納されている。

htmlparser.jsが動作しない

弊社で独自に制作したWordPressテーマにいくつかのSEO上有用と思われる情報を掲載しようと思い、あれこれ探していたところ、JavaScriptのHTMLパーサーをライブラリを見つけた。

John Resig – Pure JavaScript HTML Parser

JavaScriptは元々Domパーサーできるじゃんと思われる方も多いと思うが、今回やりたかったのは外部のHTMLをパースしたかったので、このようなライブラリが必要だった。

で、結論。

動きませんでした。

原因は、prototype.jsによるものらしい。

prototype.jsはその機能上配列やオブジェクトを汚染してしまうので、どうしても相性というのが生じてしまう。

素直にPHP側でパースして処理を行うことで解決した。

ちなみにやりたかったことはこんなこと。

wp

WordPressを企業サイトに納入する際に、うちではダッシュボードもカスタマイズしているのですが、今回はこのダッシュボードの右側の部分。

XMLに対するSafariのgetElementsByTagName()

JavaScriptでRSSをパースするスクリプトを作成してテストしていたら、Safariでだけうまく動作しなかった。

いろいろテストしてみたら、以下のような部分に問題があったことがわかった。

var siteLink = chnl.getElementsByTagName('link')[0].childNodes[0].nodeValue;

RSSのほうでは以下のような感じ。

-- 中略 --
<channel>
 <title>デジタルカタログ制作のデジパン</title>
 <atom:link href="http://www.digipan.jp/feed" rel="self" type="application/rss+xml" />
 <link>http://www.digipan.jp</link>
-- 中略 --

どうやら、Safariは名前空間atomのlink(atom:linkという要素)もgetElementsByTagName(‘link’)で拾ってしまうらしい。

IEやFirefoxではこのような問題はなかったが、どちらの解釈が正しいのかは不明。

そういえば、昔はFirefoxもこういう解釈だった気がするけど気のせい?

XML文字列をDOMエレメントに変換する

先日公開したJavaScriptでクロスドメインでのXMLアクセスを可能にするライブラリ「CrossOver」は、コールバック関数への引数がXML形式のテキストデータです。

DOMオブジェクトで戻せば余計な処理をゴリゴリ書く必要がなくて、親切だったのかもしれませんが、XML.ObjTreeなどの他の優秀なライブラリとの連携を前提にすることで、最小限の機能だけを提供することが可能になり、信頼性の確保が可能になると考えました。

それに実は私、アクションスクリプトは詳しくありません。

ただ、そうはいっても、やっぱりDOM操作をゴリゴリやりたいという声も多いようなので、XML形式のテキストデータをDOMオブジェクトに変換する関数を書いておきます。

// xmlStringをDOMオブジェクトに変換
function parseFromString( xml ){
  var root;
  if ( window.DOMParser ) {
    var xmldom = new DOMParser();
    xmldom.async = false;
    var dom = xmldom.parseFromString( xml, "application/xml" );
    if ( ! dom ) return;
    root = dom.documentElement;
  } else if ( window.ActiveXObject ) {
    xmldom = new ActiveXObject('Microsoft.XMLDOM');
    xmldom.async = false;
    xmldom.loadXML( xml );
    root = xmldom.documentElement;
  }
  return root;
}

CrossOverで定義したコールバック関数に渡された値を上記関数に渡してやると、戻り値がDOMオブジェクトに変身します。

CrossOver – JavaScriptでクロスドメイン

JavaScriptでは、セキュリティ上の制限により、違うドメインのXMLを読み込むことができません。

一方Flashでは、crossdomain.xmlにより許可されたドメインからはXMLの取得が可能です。

そこで、FlashのExternalInterfaceを利用して、JavaScript側で指定したURLからFlashでXMLを取得して、その結果をJavaScriptに返すだけの小さなswfファイルを作成しましたので公開します。

まずは、こちらのサンプルページをご覧ください。

ダウンロード

ダウンロード(CrossOver.zip)

パッケージ内容

PHPやCGIが不要です!

  1. CrossOver.swf
  2. CrossOver.js
  3. swfobject.js

利用方法

</body>の直前あたりに以下のソースを貼り付けてください。
パスは環境にあわせて修正願います。

<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="CrossOver.js"></script>

ボタンクリックなどのイベントでloadCrossOver()という関数を実行してください。
引数には、コールバック関数名及びXMLのURLを渡してください。
(コールバック関数名はダブルクォーテーション等で囲む必要があります。)

また、XMLリクエストが成功した際に実行されるコールバック関数を定義してください。

詳細は、サンプルページなどもご参照ください。

// XMLHttpリクエストをFlashにしてもらう関数
oButton.onClick = function{
  loadCrossOver( 'callback', 'http://example.com/feed.xml' );
}
// 上記関数の第一引数と同じ名前の関数を定義
function callback( XMLString ){
.......... // XMLに対する処理
}

コールバック関数の引数には、取得したXMLのString型データが渡されますので、XML.ObjTree等と併用することで、オブジェクトとして利用可能です。

ライセンス

MITライセンスとします。

ご注意

crossdomain.xmlで許可されていないサイトのXMLにはアクセスできません。
他の手を考えましょう。

JavaSCriptを圧縮 – yuicompressor

JavaScriptやCSSを圧縮してくれるyuicompressorは、それ自体はとても便利なのですが、コマンドが長くて若干めんどくさくないですか?

alias yuicomp="java -jar ~/yuicompressor-2.4.1/build/yuicompressor-2.4.1.jar --charset UTF-8 -o"

以上のような行を.bash_profileに入れると、コマンド入力が簡単になります。

適用前

java -jar ~/yuicompressor-2.4.1/build/yuicompressor-2.4.1.jar --charset UTF-8 -o out.js in.js

適用後

yuicomp out.js in.js

IEでGoogleMapのアイコンが表示されない

Googleマップを使ったアプリケーションの開発をしていて、ieでのみ地図上のカスタムアイコンがうまく表示されなかったので、若干はまってしまった。

結局、原因はiconSizeに指定した数値が、実際の画像のサイズより小さかったため。

icon.iconSize = new GSize(51, 51);

実際の画像のサイズがいつの間にか52pxになっていたので、51pxに修正したら直った。

これは予想外

住所からGoogle MAPに変換する(JavaScript編)

このサイトでは、PHPのSmartyプラグインで、住所からGoogle MAPに変換するプラグインを作成して公開しています。

あちらこちらで宣伝させていただいたら、なかなか好評で、ちょっと自己満足に浸ってたのですが、よく考えたらこのプログラムって、やってることのほとんどはJavaScriptじゃんということに気がついてしまいました。

そういうわけで、JavaScriptのみで同様の機能を提供するクラスを作成したので公開します。

ダウンロード

このクラスを使用すると、以下のようにid属性にaddrが指定された要素内のテキストを住所と見なして、id属性がgmapの要素内にGoogle Mapを挿入します。

<div id="addr">東京都千代田区永田町1-7</div>
<div id="gmap"></div>

JavaScript側の記述は、<head>〜</head>内で、「Google Maps API」、「Google Ajax Search API」、「prototype.js」と、このクラスファイルを<script src=”…”></script>して、bodyの下の方に以下の記述を入れれば完了です。

<script type="text/javascript">//<![CDATA[
var gmap = new addr2gmap();
gmap.display();
//]]></script>

PHP+Smarty版と比較すると若干めんどくさいのですが、ほとんどの環境で手軽に利用できるのがメリットです。

先に紹介した、PHP+Smarty版も同じくですが、CMSなどの会社概要のページに地図を表示させたい際に手軽にGoogle MAPが利用可能なように作成していますので、あえて低機能です。

マッシュアップなんて大それた用途ではなく軽い感じで使いたいという方にご利用いただけると嬉しい限りです。

ライセンス

MITライセンスとします。
ただし、気に入っていただけた方からの寄付は歓迎します。