最短経路検索を使ってみた

株式会社シリウステクノロジーが提供してくださっている最短経路検索を使えば、自転車でヒルクライムしようぜ!のコース登録が楽になるなぁと思った。いちいちチマチマとクリックしていく手間が省けるのだ。これは素晴らしい!と。それで現在、開発環境で試してるんだけど、いささか精度が悪い。まあ、首都圏内だと精度がいいらしいけれど、地方になると若干精度が落ちるようだ。

ひとまず、使用に耐えるレベルだった。あとの細かな修正は、例えば「点を1つ戻す」で戻りながら調節すればよいかなと。しかし、こいつをを使うと点を打ちすぎるせいか、今度は高度検索のWebAPIへのアクセスが多すぎるようになるらしく、高低表の画像を出力するときにエラーになってしまった。うーむ、あちらが立てば、こちらが立たず。というわけでリリースは延期です。

たしか、どっかのサイトで、高度検索APIの機能を自分のサーバに実装するためのノウハウが載っていたので、今度はそいつを実装してみてから考えるか。ただ、めっちゃ処理重そうだな。。。開発環境では動いても、レンタルサーバで動かなかったら、どうしよう。。。

xreaのサーバは安くていいけど、現在の環境はphp5がCGIで動いてるせいで、すげー重たく感じる。いや、俺のプログラムが重いのか?


SOAP 結合テスト

php-soapを使った、SoapClientと、javaでのSoapServerでの結合テストが行われた。こちらは仕様書通りのSOAPメッセージを出しているから、バッチリだろう。そう思っていた。

すると、まずSOAPのバージョンから違った…。俺が実装してたのは、仕様書に載っていたSOAP1.2で、SoapServerが実装してたのはSOAP1.1だった。いきなり仕様書通りじゃないとは!

しかしこちらはクライアントなので、サーバに合わせなければならない。あれをこうして、それをああして、という話を聞いている間に、仕様書には書かれてないSOAPメッセージになった…。

とりあえず、修正したSOAPメッセージを使ったところ、通信できた。まあ一応よかった〜という話にはなったが、じゃああの仕様書は一体なんだったんだろう…。お客さんから届いた仕様書の通りに作ったのに、違いますって言われても…。違うのは仕様書ってことになるやん。その仕様書はお客さんからもらってるんだけど…。

まずは通信ができることを最優先するみたいだが、SOAP1.2を使う予定だったのに1.1で実装しているSoapServerが他のWebAPIで問題になるんじゃないかとヒヤヒヤしている。まあそれもテストをしていればわかることだが。

ちなみにスタブで使ってたphpのSoapServerでは、オプションでsoap_version => SOAP_1_1にして、クライアントはsoap_version => SOAP_1_2にしても、なぜか通信できてたみたい。柔軟に対応してくれるってことか?


php-soapでわかったこと

色々とあって、php-soapやってますが、わかったことがあるので載せときます。
たしか、こんな感じにしたと思う。

◆SOAPメッセージの要素を入れ子にする方法(wsdlなし)

$options = array(
'soap_version' => SOAP_1_2,
'location' => 'http://example.net', // SoapServerのURL
'uri' => 'http://example.net/namespace/', // 名前空間のURL
'trace' => true, // トレースOKにするか否か
'exceptions' => false // SoapFault型の例外をスローするか否か
);
$obj_soap_client = new SoapClient(null, $options);  // wsdlなし、オプションは各自適当にしてネ

$ar_children = array(
new SoapVar($obj_a, SOAP_ENC_OBJECT, null, null, 'child'),
new SoapVar($obj_b, SOAP_ENC_OBJECT, null, null, 'child'),
new SoapVar($obj_c, SOAP_ENC_OBJECT, null, null, 'child'),
);
$obj_parent = new SoapVar($ar_children, SOAP_ENC_OBJECT, null, null, 'parent');
$response = $obj_soap_client->something($obj_parent); // somethingメソッドはSoapServerで定義されてること

◆もっともっと、入れ子にする方法

$ar_children = array(
new SoapVar(3, XSD_INTEGER, null, null, 'number'),
new SoapVar(array(
new SoapVar(170, XSD_INTEGER, null, null, 'height'),
new SoapVar(65, XSD_INTEGER, null, null, 'weight'),
new SoapVar('Aさん', XSD_STRING, null, null, 'name'),
), SOAP_ENC_OBJECT, null, null, 'child'),
new SoapVar(array(
new SoapVar(190, XSD_INTEGER, null, null, 'height'),
new SoapVar(100, XSD_INTEGER, null, null, 'weight'),
new SoapVar('Bさん', XSD_STRING, null, null, 'name'),
), SOAP_ENC_OBJECT, null, null, 'child'),
new SoapVar(array(
new SoapVar(175, XSD_INTEGER, null, null, 'height'),
new SoapVar(80, XSD_INTEGER, null, null, 'weight'),
new SoapVar('Cさん', XSD_STRING, null, null, 'name'),
), SOAP_ENC_OBJECT, null, null, 'child'),
);
$obj_parent = new SoapVar($ar_children, SOAP_ENC_OBJECT, null, null, 'parent');
$response = $obj_soap_client->something($obj_parent); // somethingメソッドはSoapServerで定義されてること

◆SoapServerからの戻り値について
なんと、stdClassで戻ってきやがる!
こちらは完全に連想配列のつもりでいたんで(まあこれは俺の完全な思い込みからだけど)、俺が準備したスタブの値(連想配列)で動いていたほかの人のプログラムにもろに支障が出た。うーん、戻り値を配列にするフラグくらいあるだろうと思ってネットで検索したが、めぼしいものは見つからなかった。一応、SoapClientのコンストラクタのオプションで

$options = array(
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
);

というのがあったが、これはどうやら戻り値が1つの場合でも配列っぽくするよという意味っぽい(あくまでstdClassのメンバ変数でだろうけど)。

仕方がないので、stdClassを配列にキャストした。
その際、戻り値のみを

$response = (array)$response;  // stdClassオブジェクトを配列にキャスト

とした場合、1次元しか配列にキャストされないので、戻り値が多次元の場合、再帰で処理しないといけないことに注意!(再帰のプログラムは先輩が作ってくださった。ありがとうございます!)

php-soapの情報はあんまりなかったので(見つけられなかったので?)、こういうメモが多くの人の役に立つことを祈ります。


サイクルスポーツに載りました

自転車で通勤しましょ♪が、サイクルスポーツ9月号の121ページで紹介されました!

最初はメールで取材のご連絡をいただき、まことに恐縮でしたが、サイトの売りなどを書かせていただきました。それを基にして書いていただいたのですが、こんなによく書いていただくとなんだか恥ずかしいですね〜。雑誌には色々と載せていただいたことがありますが、自転車雑誌はたぶん初めてだと思います。サイクルスポーツは学生の頃からよく読ませてもらってます!!

私はもちろん買いましたwいや〜嬉しいな〜!!


SOAPについて調べたことなどを書く

現在の案件でPHPでSOAPを使うことになったので、それについてちょっとメモ書きをしときます。
今回はPHP5なので、php-soapを使うこととした。

今回の問題点は、SOAPサーバがないのにSOAPクライアント作れって言われてるところ。
SOAPクライアントの動作を試すために、ダミーのSOAPサーバも作らなくてはならない。
まあ問題は他にもたくさんあるけれど、守秘義務ってことで!!

◆SoapClientについて
・インスタンス生成時のオプションについて
style・・・SOAP_RPC,SOAP_DOCUMENTの2種類がある。SOAP_DOCUMENTにしたら、SOAPの文字列になるだけっぽい。SOAP_RPCの場合(基本的にこっちが主流?)、サーバ側に準備されているメソッドをコールするのだが、自動的にenv:Bodyの第一要素名がコールされるメソッド名になる。

・名前空間の定義について(WSDLなしで)
なんか、自動的にns1とかns2とか振られる。こっちで制御できんのか?
SoapClientだと仕様書通りのXMLが生成できなかったので、domDocumentオブジェクトを使ってXMLを作った。

◆SoapServerについて
SoapServerは、SOAP_RPCでくるのを前提として待ち構えてる?
仕様書通りのSOAPドキュメントを作成して送信したら、第一要素名のメソッドが定義されてないって怒られた。SoapClient側で__doRequestメソッドを使ってSOAPアクションを指定しても、同様。

SOAPは初めてだけど、奥が深そうです。
しかし、開発の順序として、SOAPサーバがあってからだろ!と突っ込まざるを得ない。