by Hippo2000(2001/5/23,2002/5/25)
SOAP::Liteモジュールなのです。ホームページはSOAPLITE.COM http://soaplite.com/ になります。
ここにはユーザーガイド(http://guide.soaplite.com/)、クックブック( http://cookbook.soaplite.com/)があります。
こちらの情報についてはこれからチョー訳を考えたいと思っています。
なおこのSOAP-Liteのディストリビューションには以下のドキュメントも入っています。
合わせてご覧ください。
ファイル/モジュール 説 明 Apache::SOAP 最小限の設定でSOAPサーバーの機能を提供 SOAP::Test SOAP::Liteのためのテスト・フレームワーク SOAP::Transport::FTP SOAP::Liteのためのクライアント側FTPサポート SOAP::Transport::HTTP SOAP::Liteのためのサーバ/クライアント側HTTPサポート SOAP::Transport::IO SOAP::Lite のサーバー側IOサポート SOAP::Transport::LOCAL SOAP::Liteのためのクライアント側での転送なしのサポート SOAP::Transport::MAILTO SOAP::Liteのためのクライアント側 SMTP/sendmail サポート SOAP::Transport::POP3 SOAP::Liteのためのサーバー側POP3サポート SOAP::Transport::TCP SOAP::Liteのためのサーバー/クライアント側TCPサポート SOAPsh.pl SOAP呼び出しのための対話的なシェル UDDI::Lite PerlでのUDDIクライアントのためのライブラリ XML::Parser::Lite 正規表現ベースの軽いXMLパーザー XMLRPC::Lite XML-RPCプロトコルのクライアントとサーバーの実装 XMLRPC::Transport::HTTP XMLRPC::Liteのためのサーバー/クライアント側 HTTPサポート XMLRPCsh.pl XML RPC呼び出しの対話的なシェル
なおこのドキュメントはCPAN-Searchで出てきたドキュメント(PODを変換したもの)を日本語に訳そうとしたものです。わかりにくい部分は本物を見てください。(^^;;
原本の著作権はPaul Kulchenko さんがお持ちです。
Paul Kulchenko さんにはメールで了解をいただきました。なお内容等が間違っていたら修正します。ご連絡ください。
=更新履歴=
まこと@FESさんの指摘を受けて誤字を修正 (2002/5/25)
SOAP::Lite - クライアントおよびサーバー側SOAP実装
use SOAP::Lite;
print SOAP::Lite
-> uri('http://www.soaplite.com/Temperatures')
-> proxy('http://services.soaplite.com/temper.cgi')
-> f2c(32)
-> result;
同じことをautodispatchで:
use SOAP::Lite +autodispatch =>
uri => 'http://www.soaplite.com/Temperatures',
proxy => 'http://services.soaplite.com/temper.cgi';
print f2c(32);
OOスタイルのコード:
use SOAP::Lite +autodispatch =>
uri => 'http://www.soaplite.com/Temperatures',
proxy => 'http://services.soaplite.com/temper.cgi';
my $temperatures = Temperatures->new(32); # オブジェクトの取得 print $temperatures->as_celsius; # メソッドの呼び出し
サービス説明つきのコード:
use SOAP::Lite;
print SOAP::Lite
-> service('http://www.xmethods.net/sd/StockQuoteService.wsdl')
-> getQuote('MSFT');
SOAPサーバーのためのコード(CGI):
use SOAP::Transport::HTTP;
SOAP::Transport::HTTP::CGI
-> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method')
-> handle;
Visual Basic クライアント(COMインターフェースを通して):
MsgBox CreateObject("SOAP.Lite").new( _
"proxy", "http://services.xmethods.net/soap", _
"uri", "urn:xmethods-delayed-quotes" _
).getQuote("MSFT").result
mod_soap はSOAPサーバーを可能にします:
.htaccess
SetHandler perl-script PerlHandler Apache::SOAP PerlSetVar dispatch_to "/Your/Path/To/Deployed/Modules, Module::Name"
ASP/VB SOAP サーバー:
<%
Response.ContentType = "text/xml"
Response.Write(Server.CreateObject("SOAP.Lite") _
.server("SOAP::Server") _
.dispatch_to("/Your/Path/To/Deployed/Modules") _
.handle(Request.BinaryRead(Request.TotalBytes)) _
)
%>
SOAP::Lite はクライアント、サーバー側の両方でSimple Object Access Protocol (SOAP)への簡単で軽いインターフェースを提供するPerlモジュールの集まりです。
このバージョンのSOAP::LiteはSOAP1.1仕様( http://www.w3.org/TR/SOAP )をサポートしています。
このライブラリの主な機能は以下のとおりです:
クライアント側の例についてはt/*.t, examples/*.pl そしてモジュール・ドキュメントをご覧ください。SOAPリクエストのシリアライゼーション、HTTP経由でサーバーへの送信、レスポンスの受信そしてレスポンスのデシリアライゼーションをデモンストレートしています。サーバー側の実装についてはexamples/server/* をご覧ください。
このライブラリにより提供されるクラスの概要を以下の表にしめします:
SOAP::Lite.pm -- SOAP::Lite -- すべてのロジックを提供するメイン・クラス -- SOAP::Transport -- 転送アーキテクチャをサポート -- SOAP::Data -- シリアライゼーション・アーキテクチャのための拡張を提供 -- SOAP::Header -- ヘッダ・シリアライゼーションのための拡張を提供 -- SOAP::Parser -- XMLファイルを解析し、オブジェクト・ツリーにします -- SOAP::Serializer -- データ構造をSOAPパッケージにシリアル化 -- SOAP::Deserializer -- SOAP::Parserの結果をオブジェクトにデシリアル化 -- SOAP::SOM -- デシリアライズされたオブジェクト・ツリーへのアクセスを提供 -- SOAP::Constants -- 共通定数へのアクセスを提供 -- SOAP::Trace -- トレース機能を提供 -- SOAP::Schema -- スキーまのためのアクセスとスタブを提供 -- SOAP::Schema::WSDL -- SOAP::SchemaのためのWSDL実装 -- SOAP::Server -- サーバー側でのリクエストを取り扱う -- SOAP::Server::Object -- 参照によるオブジェクトを取り扱う -- SOAP::Fault -- サーバー側でのFaultsのサポートを提供
SOAP::Transport::HTTP.pm -- SOAP::Transport::HTTP::Client -- HTTP 転送へのクライアント・インターフェース -- SOAP::Transport::HTTP::Server -- HTTP 転送へのサーバー・インターフェース -- SOAP::Transport::HTTP::CGI -- サーバー・インターフェースのCGI 実装 -- SOAP::Transport::HTTP::Daemon -- サーバーインターフェースのデーモン実装 -- SOAP::Transport::HTTP::Apache -- サーバー・インターフェースのmod_perl実装
SOAP::Transport::POP3.pm -- SOAP::Transport::POP3::Server -- POP3 プロトコルへのサーバー・インターフェース
SOAP::Transport::MAILTO.pm -- SOAP::Transport::MAILTO::Client -- SMTP/sendmailへのクライアント・インターフェース
SOAP::Transport::LOCAL.pm -- SOAP::Transport::LOCAL::Client -- ローカルな転送へのクライアント・インターフェース
SOAP::Transport::TCP.pm -- SOAP::Transport::TCP::Server -- TCPプロトコルへのサーバー・インタフェース -- SOAP::Transport::TCP::Client -- TCPプロトコルへのクライアント・インターフェース
SOAP::Transport::IO.pm -- SOAP::Transport::IO::Server -- IO転送へのサーバー・インターフェース
SOAP::Liteが提供するすべてのメソッドは値の設定と取り出しの両方のために使うことができます。なにもパラメータを与えなければ、現在の値を取得することができます。そしてパラメータが与えられると新しい値がオブジェクトに代入され、問題のメソッドは(他に何も書かれてなければ)現在のオブジェクトを返します。これは呼び出しを以下のように積み重ねるのに便利です。
$lite = SOAP::Lite
-> uri('http://simon.fell.com/calc')
-> proxy('http://soap.4s4c.com/ssss4c/soap.asp')
;
順番はあまり重要ではなく、最初にnew()メソッドを呼び出すことができます。そうしなければSOAP::Liteはあなたに代わって、それをします。しかしnew()メソッドは追加の書き方を提供します:
$lite = new SOAP::Lite
uri => 'http://simon.fell.com/calc',
proxy => 'http://soap.4s4c.com/ssss4c/soap.asp'
;
transport->proxy()のショートカット。これはエンドポイント(サービス・アドレス)を指定させます、そして同時に必要なモジュールをロードします。SOAP呼び出しをdispatchさせるために必要です。モジュールの名前はエンドポイントに特有のプロトコルに依存して決まります。接頭語SOAP::Transport
がprependedされるでしょう、モジュールがロードされ、クラスのオブジェクト(::Clientが後ろについて)が作成されます。
SOAP::Transport:HTTP::Clientで探されます。
エンドポイント・パラメータに加えて、 proxy() は名前=>値で渡された転送特有のパラメータを受け取ることができます。例えばHTTPプロトコルのためのプロキシー設定を指定するには、以下のようにすることができます:
$soap->proxy('http://endpoint.server/',
proxy => ['http' => 'http://my.proxy.server/']);
プロキシー(2番目のもの)は1つ以上のパラメータを取ることを予想しているので、それらを配列にくるまなけばならないことに注意してください。
もう1つの便利な例はクッキー・ベースの認証を感知するクライアントにすることができます。それは以下のようにします:
$soap->proxy('http://localhost/',
cookie_jar => HTTP::Cookies->new(ignore_discard => 1));
以下のようにしてHTTP転送のためにタイムアウトを指定することができます:
$soap->proxy('http://localhost/', timeout => 5);
serializer->autotype()のショートカット。これはシリアライザがあなたに代わって自動タイピングをするかどうかを指定させます。デフォルトの設定はtrueです。serializer->readable()のショートカット。これは作成されるXMLコードのためのフォーマットを指定させます。改行(<CR>)とインデントが読みやすさのためにに加えられます。生成されたコードをデバッガで見たい場合に便利です。デフォルトでは生成されたXMLk−ドに何も追加の文字はありません。serializer->namespace()の.ショートカット。生成されるエンベロープのデフォルトの名前空間を指定させます。
(デフォルトでは'SOAP-ENV' )。serializer->encodingspace()のショートカット。生成されるエンベロープのためのデフォルトのエンコーディング名前空間を指定させます(デフォルトは'SOAP-ENC'
)serializer->encoding()のショートカット。生成されたエンベロープのためのエンコーディングを指定させます。現在のところ、実際にはエンベロープのエンコーディングを変更せず、XMLヘッダを変更するだけです(デフォルトでは'UTF-8')serializer->typelookup()のショートカット。自動タイピングのために使われるtypelookup
テーブルへのアクセスを提供します。詳細については"SOAP::Serializer"をご覧ください。
serializer->uri()のショートカット。SOAPメソッドのためのuriを指定させます。デフォルトでは何も指定されません。必要なuriを指定しなければ、呼び出しは間違いなく失敗するでしょう。警告: URI は単なる識別子です。URLのように見えるかもしれませんが、どこかをさしている保証はありませんし、そのようなポインタのように扱われるべきでもありません。URIはすべてのXMLドキュメントの空間においてユニークであると仮定されます。そこでユニークな識別子以外の何者でもないと考えられます。
serializer->multirefinplace()のショートカット。もしtrueであれば、シリアライザは最初のリファレンスの並びで多重参照(multireferences)のための値を出力します。そうでなければ、Bodyの中のmethod要素の直ぐ後にトップの独立要素としてエンコードされます。デフォルトの値はfalse。serializer->header()のショートカット。生成されるエンベロープのヘッダを指定させます。"SOAP::Data"クラスを使って、root,
mustUnderstand
またはそれ以外のすべてのヘッダを指定することができます。
$serializer = SOAP::Serializer->envelope('method' => 'mymethod', 1,
SOAP::Header->name(t1 => 5)->mustUnderstand(1),
SOAP::Header->name(t2 => 7)->mustUnderstand(2),
);
これは以下のようにシリアライズされます:
<SOAP-ENV:Envelope ...attributes skipped>
<SOAP-ENV:Header>
<t1 xsi:type="xsd:int" SOAP-ENV:mustUnderstand="1">5</t1>
<t2 xsi:type="xsd:int" SOAP-ENV:mustUnderstand="1">7</t2>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<namesp1:mymethod xmlns:namesp1="urn:SOAP__Serializer">
<c-gensym6 xsi:type="xsd:int">1</c-gensym6>
</namesp1:mymethod>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP::Header
パラメータを他のパラメータに混ぜることができます。またリモート呼び出しの結果としてSOAP::Header
を返すこともできます。例としてMy::Parameters::addheadertをご覧ください。
print SOAP::Lite
-> new(....)
-> call('myprefix:method' => @parameters)
-> result;
この例はクライアント側でのみ機能します。サーバー側で接頭辞を変更したければ、デフォルトのシリアライザをオーバーライドする必要があります。例はexamples/server/soap.* をご覧ください。
print SOAP::Lite
-> new(....)
# 最初のパラメータでCLASS名を指定することを忘れないでください。
-> call(new => @parameters)
-> result;
my $obj = CLASS->new(@parameters); print $obj->method;
しかしautodispatch の副作用として、代わりにcall()を使って以下のような書き方も可能です:
# uri()を指定しなければなりません
my $soap = SOAP::Lite
-> uri('http://my.own.site/CLASS') # <<< CLASS goes here
# ..... その他のパラメータ
;
my $obj = $soap->call(new => @parameters)->result; print $soap->call(method => $obj)->result; # 必要であれば$obj オブジェクトはここでは更新されません、 # $obj->method()tmethod()が$objを更新するように
# 変更されたオブジェクトの更新はサーバーがSOAP::Liteではない別の場所にあれば # 動かないかも知れません
print SOAP::Lite
-> new(....)
-> call(SOAP::Data->name('method')->attr({xmlns => 'mynamespace'})
=> @parameters)
-> result;
すべての属性とメソッドの名前になるSOAP::Data要素の名前を指定することができます。属性を除いては無視され、パラメータは通常どおりに提供されます。
このメソッドを使ってより多くの制御ができますが、先にuri()呼び出しをしていたとしても明示的にメソットのため名前空間属性を指定しなければならないことに注意してください。そのためメソッド要素に名前空間を持っていなければならないならば、以下のような代わりに
print SOAP::Lite
-> new(....)
-> uri('mynamespace') # will be ignored
-> call(SOAP::Data->name('method') => @parameters)
-> result;
このようにしてください
print SOAP::Lite
-> new(....)
-> call(SOAP::Data->name('method')->attr({xmlns => 'mynamespace'})
=> @parameters)
-> result;
前の呼び出しでのuri()は無視され、名前空間は指定されません。(推奨されるように)-wオプションをつけてスクリプトを実行すると以下のような警告がでます:
URI is not provided as attribute for method (method)
さらにプレフィックスをつけて呼び出そうとすると致命的なエラーになります:
print SOAP::Lite
-> new(....)
-> uri('mynamespace') # will be ignored
-> call(SOAP::Data->name('a:method') => @parameters)
-> result;
これは以下のようになります:
Can't find namespace for method (a:method)
というのも何もプレフィックス'a'に結び付けられていないからです
さらにもう1つコメント。SOAP::Liteがあなたが指定したものを変更してしまう1つのケースにはプレフィックス付の名前を指定し、名前空間名を指定しなときがあります:
print SOAP::Lite
-> new(....)
-> uri('')
-> call('a:method' => @parameters)
-> result;
これは以下のようなものを生成します:
<method xmlns="">....</method>
このようにではありません
<a:method xmlns:a="">....</method>
というのも後者はXML名前空間の仕様上、許されないからです。
他のすべての点では->call(mymethod =>
@parameters) は->mymethod(@parameters)と同義語です。
use SOAP::Lite ...
インターフェースで指定されたグローバルなデフォルト・オブジェクトへのオブジェクト・リファレンスを返します。クラス・メソッドとオブジェクト・メソッドの両方ともグローバルオブジェクトへのリファレンスを返します、そのため: use SOAP::Lite
proxy => 'http://my.global.server'
;
my $soap = SOAP::Lite->proxy('http://my.local.server');
print $soap->self->proxy;
これは 'http://my.global.server' (SOAP::Lite->self->proxyと同様に)を出力します。詳細は"デフォルト設定"
をご覧ください。
use
SOAP::Lite ...
節でしか使うことができません、そして最初に指定されなければなりません: use SOAP::Lite
dispatch_to => ['A', 'B'], # 1つのクラスには "dispatch_to => 'A'" としてください
uri => ....,
proxy => ....,
;
A->a; B->b;
SOAP要素に値、名前、型、uri、属性を指定したいときにこのクラスを使うことができます(それぞれvalue(),
name(), type(), uri() and attr()
メソッドを使って)。例えば、SOAP::Data->name('abc')->value(123)は<abc>123</abc>にシリアライズされます。またSOAP::Data->name(abc=>123)とすることもできます。(value()メソッドを除いて)それぞれは値を2番目のパラメータとして受け取ることができます。すべてのメソッドはパラメータがなしで呼び出すと、現在の値を返します。そうでなければそのオブジェクトが返されるので、それらを重ねることができます。さらなる例はtestsをご覧ください。これらのメソッドを以下のようにしてインポートすることができます:
SOAP::Data->import('name');
または
import SOAP::Data 'name';
そして短く name(abc => 123)
とすることができます。
特定の要素のためのインターフェースも提供されています。ctor(),
mustUnderstand(), encodingStyle()
そして root() を対応する属性の値を設定/取得するために使うことができます。
SOAP::Data
->name(c => 3)
->encodingStyle('http://xml.apache.org/xml-soap/literalxml')
これは以下のようにシリアライズされます:
<c SOAP-ENV:encodingStyle="http://xml.apache.org/xml-soap/literalxml"
xsi:type="xsd:int">3</c>
通常はこのモジュールと直接対話する必要はありません。必要な唯一のケースは自動タイピングを使うときです。この機能は(例えば順序付のハッシュのような)新しいデータ型を導入したい、あなたの必要にしたがってデータのための型を指定させます。
SOAP::Data->type(float => 123)で型を指定することができます。シリアライゼーションの段階では、モジュールはas_floatメソッドでデータをシリアル化しようとします。それがtypecastメソッドを呼び出すと(オーバーライドしたり"SOAP::Data"から継承することができます)データ型(SCALAR、ARRAYまたはHASH)に従っってそれをシリアライズしようとします。例えば:
SOAP::Data->type('ordered_hash' => [a => 1, b => 2])
これはas_ordered_hashメソッドを使って、順序付のハッシュといしてシリアライズされます。
直接、型を指定しなければ、serialization モジュールはtypelookupハッシュに従って、あなたの代わりに自動判定しようとします。そのtypelookupハッシュには型名をキーとし以下の3つの要素の配列が値として入っています:
優先順位、 チェック関数(コードリファレンス)、 typecast関数 (メソッド名もしくはコード・リファレンス)
例えばuriReferenceを自動判定される型に追加したければ、以下のようなものを追加しなければなりません:
$s->typelookup->{uriReference} =
[11, sub { $_[0] =~ m!^http://! }, 'as_uriReference'];
そして"SOAP::Serializer"クラスにas_uriReferenceメソッドを追加します:
sub SOAP::Serializer::as_uriReference {
my $self = shift;
my($value, $name, $type, $attr) = @_;
return [$name, {'xsi:type' => 'xsd:uriReference', %$attr}, $value];
}
指定されたメソッドは自動タイピングでも直接データ型設定でも使われます。そのため以下のいずれも使うことができます:
SOAP::Data->type(uriReference => 'http://yahoo.com')>
もしくは単に
'http://yahoo.com'
そしてそれらは同じ型にシリアライズされます。さらなる例については"SOAP::Serializer"でのas_*メソッドをご覧ください。
SOAP::Serializer はautotype(), readable(),
namespace(), encodingspace(), encoding(),
typelookup(), uri(), multirefinplace()
そしてenvelope()メソッドを提供します。すべてのメソッドは(envelope()を除いて).
All methods (except envelope()) "SOAP::Lite"で説明されています。
envelope(method => 'methodname', @parameters);
method('methodname', @parameters);
はrequest/response エンベロープを組み立てます。
envelope(fault => 'faultcode', 'faultstring', $details);
fault('faultcode', 'faultstring', $details);
はfaultエンベロープを組み立てます。Faultcode は適切に修飾され、detailsには文字列またはオブジェクトを指定できます。
envelope(freeform => 'something that I want to serialize');
freeform('something that I want to serialize');
非RPC呼び出し他のための予約。SOAPエンベロープの内側に独自の情報を組み立てさせます。メソッド特有のものを除いて、すべてのSOAP1.1仕様規則が強制されます。例としてUDDI::Liteをご覧ください。
さらなる例としてはtestsとSOAP::Transport::HTTP.pmをご覧ください。
オブジェクト指向インタフェースを通じて行うすべての呼び出しは、SOAP::SOMオブジェクトを返します。そしてそれで実際の値にアクセスすることができます。次の例はそのクラスの簡単な概要を示します:
my $soap = SOAP::Lite .....; my $som = $soap->method(@parameters);
if ($som->fault) { # もしFault要素がそのメッセージにあればdefined
print $som->faultdetail; # 文字列またはオブジェクトとして
# 'detail'要素の値を返します
$som->faultcode; #
$som->faultstring; # 同様に使えます
$som->faultactor; #
} else {
$som->result; # 呼び出し結果へのアクセスを提供します
# あらゆるデータ構造になりえます。例えばreturn [1,2]のようにサーバーが
# したとすれば配列へのリファレンスになります
$som->paramsout; # もしあればoutパラメータへのアクセスを提供します。
# 例えば、サーバーがreturns ([1,2], 1, 2); であれば
# 配列(1,2)を取得するでしょう。
# [1,2] は$som->resultとして返されます。
# $som->paramsall は ([1,2], 1, 2) を返します。
# さらなる詳細はセクション IN/OUT, OUT パラメータと自動バインディング
# をご覧ください
$som->paramsall; # 結果と(もしあれば)outパラメータへのアクセスを与え、
# 1つの配列として返します
$som->valueof('//myelement'); # もしあれば'myelement'の値(perlデータとして)
# 返します。配列コンテキストではすべての要素、
# スカラコンテキストでは最初の要素を返します
$h = $som->headerof('//myheader'); # SOAP::Headerとして要素を返します。そのため
# 属性や値に$h->mustUnderstand, $h->actor
# または$h->attr (すべての属性用)でアクセスする
# ことができます。
}
SOAP::SOM オブジェクトは数種類のメソッドを通して、デシリアライズされたエンベロープへのアクセスを提供します。すべてのメソッドは(XPathの書き方に似ている)ノード・パスを受け取ります。
SOMは'/'をルート・ノード、'//'を相対的位置パス('/Envelope//nums'はEnvelopeノードの下にあるすべての'nums'ノードを見つけるのと同様に、'//Body'はドキュメントのなかのすべての本体(body)を探します)、'{num}はノード番号、そしてopを持った'[op num]'は比較演算子('<', '>', '<=', '>=', '!', '=')であると解釈します。
ノードセットでのすべてのノードはドキュメントでの順番に返されます。
$som->match('/Envelope/Body/[1]'); # match メソッド
$som->valueof('[1]'); # 結果
$som->valueof('[2]'); # 最初のout パラメータ (もしあれば)
返される値はコンテキストに依存します。スカラ・コンテキストではマッチしたノードセットから最初の要素を返します。配列コンテキストではマッチしたすべての要素を返します。
valueof()と同じ。しかし"SOAP::Data"
オブジェクトを返します。そのため要素の名前、型、属性にアクセスすることができます。dataof()と同じ。しかし"SOAP::Header"
オブジェクトを返します。そのため要素の名前、型、属性にアクセスすることができます。ヘッダを変更するためにも使うことができます(Header要素の内側の更新されたヘッダを見たければ、dataof()メソッドの代わりにこのメソッドをつかったほうがよいです)。 <a xmlns='http://my.namespace'>
<b>
value
</b>
</a>
このメソッドは'a'のためと同じ値を'b'についても返します。
SOAP::SOMはエンベロープ(envelope)、本体(body)、メソッド(method)そしてパラメータ(parameter)(inとoutの両方)への直接アクセスするメソッドも提供します。オブジェクト・メソッドとして呼ばれると、これらすべてのメソッドは本当の値を返します(ほとんどの場合それはハッシュ・リファレンスになります)。返される値はコンテキストによります:配列コンテキストでは値の配列を返します。そしてスカラ・コンテキストでは最初の要素を返します。そのため最初の出力パラメータにアクセスしたければ、実際の出力パラメータの数に関係なく、$param = $som->paramsout;を呼び出して取得することができます。
クラス関数として呼び出すと(例えばSOAP::SOM::method)、現在の要素にマッチするXPath文字列を返します('method'の場合は'/Envelope/Body/[1]')。このメソッドは、存在しないかまたはxsi:null="1"属性を持つ要素にアクセスしようとしたときにはundefを返します。これら2つの場合を切り分けるには、最初にmatch()メソッドでアクセスすることができます。それはブール値コンテキストではtrue/falseを返します、そして実際の値を取得します:
if ($som->match('//myparameter')) {
$value = $som->valueof; # これはundefになるかも
} else {
# 存在しない
}
if ($som->match(SOAP::SOM::envelope)) {
$som->valueof('Header'); # もしあればヘッダへのアクセスを提供
$som->valueof('Body'); # 本体へのアクセスを提供
} else {
# ウーン、SOAPをしてるんじゃないの?
}
# 要素をSOAP::Data オブジェクトとして取得 $transaction = $som->match(join '/', SOAP::SOM::header, 'transaction')->dataof; # すると'transaction'要素のすべての属性にアクセスすることができます $transaction->attr;
$som->headerof(join '/', SOAP::SOM::header, '[1]'); # 最初のヘッダをSOAP::Headerオブジェクトとして提供
($som->headers)[0]; # 最初のヘッダの値を取得、以下のものと同じ $som->valueof(join '/', SOAP::SOM::header, '[1]');
$som->header->{name_of_your_header_here}
# name_of_your_header_hereの値を提供
result(),
paramsin(), paramsout()
そして method()はundefを返します。SOAP::Schemaはスキーマをロードし、これらのスキーマに従ったスタブを作成する能力を提供します。異なった書き方が提供されます:
use SOAP::Lite
service => 'http://www.xmethods.net/sd/StockQuoteService.wsdl',
# service => 'file:/your/local/path/StockQuoteService.wsdl',
# service => 'file:./StockQuoteService.wsdl',
;
print getQuote('MSFT'), "\n";
use SOAP::Lite;
print SOAP::Lite
-> service('http://www.xmethods.net/sd/StockQuoteService.wsdl')
-> getQuote('MSFT'), "\n";
use SOAP::Lite;
my $service = SOAP::Lite
-> service('http://www.xmethods.net/sd/StockQuoteService.wsdl');
print $service->getQuote('MSFT'), "\n";
stubmaker スクリプトでスタブを作成することができます:
perl stubmaker.pl http://www.xmethods.net/sd/StockQuoteService.wsdl
そして1行でSOAPサービスにアクセスできるようになります:
perl "-MStockQuoteService qw(:all)" -le "print getQuote('MSFT')"
または動的に:
perl "-MSOAP::Lite service=>'file:./quote.wsdl'" -le "print getQuote('MSFT')"
スタブをサポートされているその他の書き方は:
use StockQuoteService ':all';
print getQuote('MSFT'), "\n";
use StockQuoteService;
print StockQuoteService->getQuote('MSFT'), "\n";
use StockQuoteService;
my $service = StockQuoteService->new;
print $service->getQuote('MSFT'), "\n";
スキーマのサポートは現在のところ限定されます。モジュールは数多くの異なるスキーマでテストされましたが、複雑なオブジェクトは理解せず、WSDLでのみ機能します。
SOAP::Trace はSOAP::Liteライブラリのためのtrace/debug機能を提供します。これを有効にするには、SOAP::Liteのトレース可能なイベント/部分のリストを指定する必要があります:
use SOAP::Lite +trace =>
qw(list of available traces here);
使用可能なイベントは以下のものがあります:
transport -- (client) 転送レイヤのためのrequest/response へのアクセス dispatch -- (server) 呼び出された呼び出しのフルネームを表します result -- (server) メソッド呼び出しの結果 parameters -- (server) メソッド呼び出しのためのパラメータ headers -- (server) 受信されたメッセージのヘッダ objects -- (both) new/DESTROY 呼び出し method -- (both) '->envelope(method =>'呼び出しのためのパラメータ fault -- (both) '->envelope(fault =>' 呼び出しのためのパラメータ freeform -- (both) '->envelope(freeform =>' 呼び出しのためのパラメータ trace -- (both) ある重要な関数へtraceを入れる debug -- (both) 転送についての詳細
例えば:
use SOAP::Lite +trace =>
qw(method fault);
は、すべての失敗/通常エンベロープのためのパラメータをSTDERRに出力させます。もしログを取りたければ、STDERRを何か他のファイルにリダイレクトさせることができます。
BEGIN { open(STDERR, '>>....'); }
または(より好まれることに)特定のイベントのための独自の関数を定義することができます:
use SOAP::Lite +trace =>
method => sub {'log messages here'}, fault => \&log_faults;
いくつかのイベントで同じ関数を共有することもできます:
use SOAP::Lite +trace =>
method, fault => \&log_methods_and_faults;
またすべての利用可能なトレースを取得するために'all'を使い、イベントの前に'-'を使うことにより特定のイベントを利用不能とすることができます:
use SOAP::Lite +trace =>
all, -transport; # to get all logging without transport messages
最後に
use SOAP::Lite +trace;
はすべてのデバッグを有効にします。
'trace'の代わりに'debug'を使うことができます。私は'trace'が好きですが、他の人は'debug'が好きです。同様に以下のように、on_debugも後方互換性のために利用可能です。
use SOAP::Lite;
my $s = SOAP::Lite
-> uri('http://tempuri.org/')
-> proxy('http://beta.search.microsoft.com/search/MSComSearchService.asmx')
-> on_debug(sub{print@_}) # show you request/response with headers
;
print $s->GetVocabulary(SOAP::Data->name('~:Query' => 'something'))
->valueof('//FOUND');
または以下のように個別に有効にします:
use SOAP::Lite +trace => debug;
もしくは
use SOAP::Lite +trace => debug => sub {'do_what_I_want_here'};
以下のものと比較してみてください:
use SOAP::Lite +trace => transport;
これは実際のrequest/responseオブジェクトへのアクセスを提供します。そのためクッキーを設定/読込をおこなったり、そこでやりたいことのすべてを行うことができます。
debugとtransportの違いはtransportはHTTP::Request/HTTP::Responseオブジェクトを取得し、debugは(オブジェクトではなく!)文字列化されたリクエストを取得することで。これは他の場所でも呼び出すことができます。
このクラスはサーバー側で生成されたFaultへのアクセスを提供します。Faultメッセージを作成するには、サーバー側で単にdieするだけです。SOAPプロセッサはfaultstring要素としてメッセージをくるみ、Faultをクライアント側へ転送します。しかしいくつかの場合には、この処理により多くの制御をする必要があり、そしてSOAP::Faultクラスはそれを提供します。これを使うには単にSOAP::Faultオブジェクトをパラメータとしてdieします。
die SOAP::Fault->faultcode('Server.Custom') # will be qualified
->faultstring('Died in server method')
->faultdetail(bless {code => 1} => 'BadError')
->faultactor('http://www.soaplite.com/custom');
faultdetail() と faultactor() メソッドはオプションで、faultcodeとfaultstringはfaultメッセージではあることが必要とされるので、もしなければSOAP::Liteはデフォルト値を使います('Server'そして'Application error')。
この機能はautodispatch と似ているように見えますが、これらは(ほとんど)共通のものを持ちません。それはデフォルト・オブジェクトを作らせ、すべてのその後に作られるすべてのオブジェクトはデフォルトからクローンされ、そのためそのプロパティを取得します。もし共通のproxy()やurt()設定をあなたのアプリケーションでのすべてのSOAP::Liteオブジェクトに提供したければ、以下のようにすることができます:
use SOAP::Lite
proxy => 'http://localhost/cgi-bin/soap.cgi',
uri => 'http://my.own.com/My/Examples'
;
my $soap1 = new SOAP::Lite; # 上と同じproxy()/uri() を取得 print $soap1->getStateName(1)->result;
my $soap2 = SOAP::Lite->new; # 上と同じ print $soap2->getStateName(2)->result;
# もしくは欲しい設定をすべてオーバーライドすることもできます
my $soap3 = SOAP::Lite->proxy('http://localhost/');
print $soap3->getStateName(1)->result;
すべての SOAP::Lite
プロパティをこのようにして伝播させることができます。オブジェクトのコピーでの変更はグローバルな設定には影響を与えません。そしてグローバル・オブジェクトへのリファレンスを返すSOAP::Lite->self
呼び出しでグローバル設定を変更することもできます。提供されたパラメータはこのオブジェクトを更新し、それをundefに設定することさえできます:
SOAP::Lite->self(undef);
use SOAP::Lite
の書き方もプログラムのためのデフォルトのイベント・ハンドラを指定させます。異なるSOAPオブジェクトを持っていて、同じon_action(もしくはそのことについてのon_fault())ハンドラを共有したいならば、各オブジェクトの初期化のさいにon_action()を指定することもできますが、以下のようにするこもとできます:
use SOAP::Lite
on_action => sub {sprintf '%s#%s', @_}
;
すると、このハンドラはあなたのすべてのSOAPオブジェクトのためのデフォルトのハンドラになります。特定のオブジェクトのためにハンドラを指定すれば、それをオーバーライドすることもできます。on_fault()ハンドラの例についてはt/*.t をご覧ください。
use ... はコンパイル時にスクリプトが実行される前にすべてのステートメントが実行されるために、予想されない結果となるかもしれないことに注意してください。以下のコードについて考えてみてください:
use SOAP::Lite proxy => 'http://localhost/';
print SOAP::Lite->getStateName(1)->result;
use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi';
print SOAP::Lite->getStateName(1)->result;
SOAP 呼び出しは両方とも'http://localhost/cgi-bin/soap.cgi'
にいきます。実行時に実行したければ、evalに入れてください:
eval "use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi'; 1" or die;
または以下のようにしてください
SOAP::Lite->self->proxy('http://localhost/cgi-bin/soap.cgi');
SOAP::Lite はすべてのパラメータへのアクセスを提供します(in/out そしてout)。そしてさらに追加の動きもします。以下のれいについて考えてみましょう:
<mehodResponse>
<res1>name1</res1>
<res2>name2</res2>
<res3>name3</res3>
</mehodResponse>
その場合:
$result = $r->result; # 'name1'を提供 $paramout1 = $r->paramsout; # スカラコンテキストなので 'name2'を提供 $paramout1 = ($r->paramsout)[0]; # 同様に 'name2'を提供 $paramout2 = ($r->paramsout)[1]; # 'name3'を提供
または
@paramsout = $r->paramsout; # outパラメータのARRAYを提供 $paramout1 = $paramsout[0]; # ($r->paramsout)[0]と同じように'res2' $paramout2 = $paramsout[1]; # ($r->paramsout)[1]と同じように'res3'
一般的に、サーバーがreturn (1,2,3)を返せば、1を結果(result)、2と3をoutパラメータとして取得します。
もしサーバーがreturn [1,2,3]を返せば、result()から配列を取得し、paramsout()からはundefを取得します。結果(result)は任意に複雑にすることができます。何かの配列にしたり、オブジェクトにしたり、何にでもすることができ、それでもresult()によって返されます。1つのパラメータが返されると、paramsout()はundefを返します。
しかしそれ以上のことがあります。もし出力パラメータに入力パラメータと同じ符号(名前+型)のパラメータを持っていれば、自動的に入力パラメータにマップされます。
サーバー
sub mymethod {
shift; # オブジェクト/クラス リファレンス
my $param1 = shift;
my $param2 = SOAP::Data->name('myparam' => shift() * 2);
return $param1, $param2;
}
クライアント
$a = 10;
$b = SOAP::Data->name('myparam' => 12);
$result = $soap->mymethod($a, $b);
こうすると、 $result == 10 そして
$b->value == 24!魔法みたいだ?ある種の自動バインディグがこれを実現しています。オブジェクト・パラメータの名前や型を心配する必要がないという1つの点を除いてオブジェクトについても同様に作用します。PingPongの例について考えてみましょう(examples/My/PingPong.pm
と examples/pingpong.pl):
サーバー:
package My::PingPong;
sub new {
my $self = shift;
my $class = ref($self) || $self;
bless {_num=>shift} => $class;
}
sub next {
my $self = shift;
$self->{_num}++;
}
クライアント:
use SOAP::Lite +autodispatch =>
uri => 'urn:',
proxy => 'http://localhost/'
;
my $p = My::PingPong->new(10); # $p->{_num} is 10 now, real object returned
print $p->next, "\n"; # $p->{_num} is 11 now!, object autobinded
警告: autodispatch 機能はUNIVERSAL::AUTOLOADのオーバーロードのために、アプリケーションに副作用を与え、他のモジュール/ライブラリに機能的な影響を与えるかもしれません。すべての未解決の呼び出しはSOAP呼び出しとして呼び出されます。場合によってはそうであって欲しくないかもしれませんが。もしそうであればオブジェクト・インターフェース(OOインターフェースの実装をご覧ください)を使うことをお考えください。
SOAP::Lite はautodispatching 機能を提供しており、これによりローカルとリモートのアクセスを同じように見えるプログラムを書くことができます。
例えば:
use SOAP::Lite +autodispatch =>
uri => 'urn:/My/Examples',
proxy => 'http://localhost/'
;
は SOAP に すべての呼び出しを'http://localhost/'エンドポイントに'urn:/My/Examples' uriで自動呼出しするように伝えます。この結果、メソッド呼び出しは以下のようになります:
print getStateName(1), "\n";
print getStateNames(12,24,26,13), "\n";
print getStateList([11,12,13,42])->[0], "\n";
print getStateStruct({item1 => 10, item2 => 4})->{item2}, "\n";
見てのとおり、SOAP特有のコーディングは何もありません。
同じロジックがオブジェクトについても機能します:
print "Session iterator\n"; my $p = My::SessionIterator->new(10); print $p->next, "\n"; print $p->next, "\n";
これはリモートのMy::SessionIterator モジュールにアクセスし、オブジェクトを取り出し、そして再びリモートのメソッドを呼び出します。オブジェクトはサーバーに転送され、メソッドがそこで実行され、結果(そして更新されたオブジェクト!)がクライアントに転送され戻ってきます。
Autodispatch は、プログラムに同じメソッドを持っていないときにだけ機能します。例えばuse My::SessionIteratorを前の例のプログラムのどこかで持っていれば、すべてのメソッドはローカルに解決され、SOAP呼び出しは何もおこなわれません。そのような場合でもリモートのオブジェクト/メソッドにアクセスしたければ、以下のようにメソッドの前にSOAP::をつけてください:
print $p->SOAP::next, "\n";
スクリプトの例としてはpingpong.pl
をご覧ください、それはローカルとリモートに同じオブジェクトで動きます。
SOAP:: 接頭辞 はSOAP::Liteそれ自身と同じ名前をもつメソッドへの任意のアクセスを提供します。たとえばOOインタフェースでクラスMy::PingPongのためのnew()メソッドを呼び出したいとします。最初にやろうとすると:
my $s = SOAP::Lite
-> uri('http://www.soaplite.com/My/PingPong')
-> proxy('http://localhost/cgi-bin/soap.cgi')
;
my $obj = $s->new(10);
しかしこれは動きません。SOAP::Liteがメソッドnew()を持っているからです。ヒントを与えるためにSOAP::を前につければ、呼び出しはリモートに呼び出されます:
my $obj = $s->SOAP::new(10);
必要であればautodispatchと通常のSOAP呼び出しを同じプログラムで混ぜることができます。SOAP::を前につけた呼び出しは常にメソッド呼び出しでなければならないことに気をつけてください。そのため関数を呼び出したければ、SOAP::myfunction()の代わりにSOAP->myfunction()を使ってください。
Perlが非常に柔軟な書き方を持っているからといっても、'autodispatch' と'=>'を別の行に置こうとすると、バージョンによっては以下のように怒らることに注意してください
Bareword "autodispatch" not allowed while "strict subs" in use ...
そのため同じ行にするか、'autodispatch'をクォートで囲むかしてください:
use SOAP::Lite 'autodispatch' # この場合にはプラスを使わないでください
=> ....
;
SOAP::Liteはサーバー側ですべてのヘッダとエンベロープ全体への直接アクセスを提供しています。My::Parameters.pmからの以下のコードについて考えてみましょう:
sub byname {
my($a, $b, $c) = @{pop->method}{qw(a b c)};
return "a=$a, b=$b, c=$c";
}
SOAP::Server::Parametersクラスからクラスを継承した場合にのみ、この機能を取得できます。これにより既存のプログラムをそのままに、必要なときにだけこの機能を提供します。
サーバー側のすべてのメソッドはクラス/オブジェクト メソッドとして呼び出されます。そのため最初のパラメータとしてオブジェクト・リファレンスまたはクラス名を、そしてメソッド・パラメータ、SOAP::SOMオブジェクトでのエンベロープを取得します。まとめると:
$self [, @parameters] , $envelope
決まった数のパラメータであれば、以下のようにすることができます:
my $self = shift; my($param1, $param2) = @_;
そしてエンベロープを無視します。エンベロープにアクセスする必要があれば、以下のようにできます:
my $envelope = pop;
というのもエンベロープは常にパラメータリストの最後の要素だからです。byname()メソッドpop->methodはパラメータ名をハッシュ・キーとし、ハッシュの値をパラメータ値とするハッシュを返します:
my($a, $b, $c) = @{pop->method}{qw(a b c)};
これは、パラメータへの名前によるアクセスを提供します。
展開プロセスについて詳しく見ていきましょう。SOAPサーバーを設計するさい、2種類の展開を考えることができます。静的(static)と動的(dynamic)です。静的と動的の両方とも、SOAP::Liteモジュールを使って作成するさいにはモジュール、モジュール::メソッド、またはパスを指定しなければなりません。静的と動的展開の違いは、「動的」な場合、要求のさいに、すべての存在しないモジュールがロードされるということです。詳しい説明については"セキュリティ" をご覧ください。
静的展開の例:
use SOAP::Transport::HTTP; use My::Examples; # モジュールはあらかじめロードされます
SOAP::Transport::HTTP::CGI
# 展開されるモジールはここになければなりません。そうでなければクライアントは「アクセスが拒否されました」('access deied')を受け取ります
-> dispatch_to('My::Examples')
-> handle;
動的展開の例:
use SOAP::Transport::HTTP; # 名前はわかりません、モジュールは要求のさいにロードされます
SOAP::Transport::HTTP::CGI
# 展開されるモジールはここになければなりません。そうでなければクライアントは「アクセスが拒否されました」('access deied')を受け取ります
-> dispatch_to('/Your/Path/To/Deployed/Modules', 'My::Examples')
-> handle;
静的展開では、モジュール名を直接指定しなければなりません。動的展開では名前を直接(その場合は何も制約なしに要求されます)またはパスで間接的に指定することができます。その場合、利用できる唯一のパスは、dispatch_to()メソッドに渡されたパスになります。この場合の取り扱いについてのさらなる情報は"セキュリティ" セクションをご覧ください。
1つのファイルの中に数多くの異なるクラスを持っているとき、それをSOAP呼び出しで使いたい場合にも、静的バインディングを使わなければなりません。
まとめ:
dispatch_to(
# 動的ディスパッチ 指定されたディレクトリのすべてのモジュールへのアクセスを可能にします
PATH/TO/MODULES
# 1. ディレクトリの指定
# -- そして --
# 2. 制限なしにこのディレクトリに入っているすべてのモジュールへのアクセスを提供
# 静的ディスパッチ 特定のモジュールのすべてのメソッドへのアクセスを可能にします
MODULE
# 1. 特定のモジュール(利用可能なすべてのメソッド)へのアクセスを提供します
# 事前に必要なこと:
# 主導でモジュールをロードされなければなりません (例えば 'use ...'で)
# -- または --
# PATH/TO/MODULESで指定することもできます
# 静的ディスパッチ 特定のメソッドだけへのアクセスを可能にします
MODULE::method
# MODULEと同じ。しかし特定のメソッドだけへのアクセスを提供します。
# そのため同じモジュールに対してMOULEとMODULE::methodの両方を指定する
# ことはあまり意味がありません
)
これに加えてSOAP::Liteは特定のURLまたはSOAPActionをCLASS/MODULEまたはオブジェクトに結びつけることを可能にする実験的な書き方をサポートしています。
dispatch_with({
URI => MODULE, # 'http://www.soaplite.com/' => 'My::Class',
SOAPAction => MODULE, # 'http://www.soaplite.com/method' => 'Another::Class',
URI => object, # 'http://www.soaplite.com/obj' => My::Class->new,
})
URI はSOAPActionの前にチェックされます。dispatch_to()とdispatch_withの両方の書き方を使うことができます。そしてdispatch_with()のほうが優先されます。そのため最初にURI、そしてSOAPActionがチェックされ、その後にdispatch_to()がチェックされます。更なる情報と例については、 t/03-server.t をご覧ください。
セキュリティ上の理由から、、動的展開を選択し、独自のPATH/を指定するとperlモジュールのためのカレント・パス(@INC)は使えなくなります。もしインクルードされるパッケージで他のモジュールにアクセスしたければ、いくつかの方法があります:
use MODULE;
$server->dispatch_to('MODULE');
展開されたモジュールから何か特定のものをインポートしたときにも便利です。
use MODULE qw(import_list);
eval 'use MODULE qw(import_list)'; die if $@;
BEGIN { @INC = qw(my_directory); use MODULE }
SOAP::Lite は送信上での圧縮を可能とするオプションを提供します(HTTP転送のみ)。サーバーとクライアントの両方でこの機能をサポートしなければなりません、しかしこのロジックはアプリケーションにとってはまったく透過的です。
圧縮はクライアントまたはサーバー側で圧縮のための閾値を指定することにより可能になります:
print SOAP::Lite
-> uri('http://localhost/My/Parameters')
-> proxy('http://localhost/', options => {compress_threshold => 10000})
-> echo(1 x 10000)
-> result
;
サーバー
my $server = SOAP::Transport::HTTP::CGI
-> dispatch_to('My::Parameters')
-> options({compress_threshold => 10000})
-> handle;
SOAP::Lite は参照によるオブジェクト(objects-by-reference)実験敵意(まだ機能的)サポートをしています。これを使うとクライアント側と違いが何も見つからないでしょう。サーバー側では、サーバー実装のためのobjects_by_reference()メソッドで参照(値ではなく)で返したいクラスの名前を指定しなければなりません(soap.pop3、soap.daemonそしてApache.pmをご覧ください)
サーバー側でガベージ・コレクションは行われます(動いていない時間が600秒後よりも早くなく)。そしてすべての特定のクラスのための特定の関数でデフォルトの動きをオーバーロードすることができます。
バイデンィグは特別な書き方はなく、サーバー側で実装されます(My::SessionIteratorとMy::PersistentIteratorとの違いをご覧ください)。クライアント側では、オブジェクトは前と同じ型/クラスを持ちます。(My::SessionIterator->new()はクラスMy::SessionIteratorのオブジェクトを返します)。しかしこのオブジェクトは内側ではオブジェクトIDを持ったスタブに過ぎません。
return SOAP::Data->name('~:myname')->type('string')->value($output);
さらに下記の.NET Webサービスでデフォルトで書かれているプログラムについてのコメントをご覧ください。
SOAP::Lite クライアントと .NET サーバー
on_action(sub{join '', @_})を使ってください。
SOAP::Data->name('Query' =>
'biztalk') の代わりに SOAP::Data->name('~:Query'
=> 'biztalk')
を使ってください。SOAPsh 呼び出しの例(すべてのパラメータは1行でなければなりません)
> perl SOAPsh.pl
"http://beta.search.microsoft.com/search/mscomsearchservice.asmx"
"http://tempuri.org/"
"on_action(sub{join '', @_})"
"GetVocabulary(SOAP::Data->name('~:Query' => 'biztalk'))"
my @rc = $soap->call(add => @parms)->result; # -- または -- my @rc = $soap->add(@parms)->result;
とする代わりに
my $method = SOAP::Data->name('add')
->attr({xmlns => 'http://tempuri.org/'});
my @rc = $soap->call($method => @parms)->result;
としてください。
SOAP::Lite は SOAP エンコーディング (soap1.1 仕様のセクション 5)を使います。そして.NET Webサービスはデフォルトではリテラル・エンコーディングを使います。そのためリクエストのなかの要素は
修飾されませんが、サービスは修飾されることを期待します。.Net Webサービスは期待されるメッセージのフォーマットを変更するための方法をもっています。これは中間の動きを取得することを可能にします。asmxでのクラスの先頭で、この属性を追加してください:
[SoapService(Style=SoapServiceStyle.RPC)]
Full Web Service テキストとは以下のようになります。 (私が書き方を理解している限りでは):
<%@ WebService Language="C#" Class="Test" %> using System; using System.Web.Services; using System.Xml.Serialization;
[SoapService(Style=SoapServiceStyle.RPC)]
public class Test : WebService {
[WebMethod]
public int add(int a, int b) {
return a + b;
}
}
説明と例について、Petr Janata <petr.janata@i.cz>, Stefan Pharies <stefanph@microsoft.com>, and Brian Jepson <bjepson@jepstone.net> に感謝します。
XML Parsers
(http://www.megginson.com/SAX/index.html).
つまり場合によっては、SOAP::Liteにより作成されたSOAPメッセージがSAX2/Javaパーザーでは適切に解析されないかもしれません。
というのもEnvelope要素は名前空間宣言とこの宣言に依存する属性がが入っているからです。XMLの仕様によれば、これらの属性の順番は重要ではなく、SOAP::Liteは何も問題なくそのようなメッセージを解析します。
これについて指摘してくれたSteve Alpert (Steve_Alpert@idx.com) に感謝します。
それは数多くの呼び出しを導き、小さなメッセージごとの追加のメモリ管理出費をかけさせます。これに対してbase64でエンコードされたXMLメッセージはこの問題がありません。そして違いは処理時間で明確です。だいたい20行、30タグを持っているXMLエンコードされた文字列は、100回ほど呼び出しがありますが、base64でエンコードされた同じ文字列は1回です。
この動きを修正しないのはパーザーの機能ですので(もし何か見つけたら教えてください)、特に既に取得したメッセージを解析する必要があるので(そしてこのメッセージの内容を制御することができないので)、しかしながらもし処理の両端について責任を持っているのであれば、送り側でbase64にエンコーディングを切り替えることができます。これはSOAP::Liteでは間違いなく動きます。他のツールキト/実装でも動くかもしれません。しかし明確にはそれを保証できません。
特定の文字列をbase64でエンコードしたければ、クライアントまたはサーバー側でSOAP::Data->type(base64
=> $string) とだけしてください。SOAP::Liteの特定のインスタンスのための動きを変えたければ、SOAP::Serializerをサブクラス化し、文字列のエンコーディングを受け持つas_string()メソッドを(as_base64()を見て)オーバーライドし、そして新しいSerializerクラスをSOAP::Liteオブジェクトに指定します:
my $soap = new SOAP::Lite
serializer => My::Serializer->new,
..... 他のパラメータ
またはサーバー側:
my $server = new SOAP::Transport::HTTP::Daemon # or any other server
serializer => My::Serializer->new,
..... 他のパラメータ
SOAP::Liteのすべてのインスタンスのこの動きを変更したければ、use SOAP::Liteの後、実際に処理/送信する前のどこかで、as_string()メソッドをas_base64()で置き換えるだけです:
*SOAP::Serializer::as_string = \&SOAP::Serializer::as_base64;
最後2つのメソッドはすべての文字列に影響を与え、それらをbase64エンコードへ変換することに注意してください。SOAP::Liteでは何も違いはありませんが、他のツールキットでは違いがあるかもしれません。
そのマシンにtelnetでアクセスし、XML::Parserが既にインストールされていれば、ホスティング・プロバイダが彼ら自身でやりたがらなくても、SOAP::Liteの独自のコピーをインストールすることができます。
ログインし、.profile(または.bash_profile)にPERL5LIB変数を設定します:
PERL5LIB=/you/home/directory/lib; export PERL5LIB
ここでの'lib' は、ホームディレクトリの下ですべてのライブラリがインストールされるディレクトリの名前です:
CPAN モジュールを以下のようにして起動します
perl -MCPAN -e shell
そして以下の3つのコマンドを実行します
o conf make_arg -I~/lib o conf make_install_arg -I~/lib o conf makepl_arg LIB=~/lib PREFIX=~ INSTALLMAN1DIR=~/man/man1 INSTALLMAN3DIR=~/man/man3
LIB じゃすべてのライブラリがあるディレクトリを指定します。
PREFIX はすべてのディレクトリのための接頭辞を指定します。(lib, bin, manのような。しかしある理由からすべての場合には機能しません)
INSTALLMAN1DIR と INSTALLMAN3DIR はmanのためのディレクトリを指定します(指定しなければ、デフォルトのディレクトリにセットアップしようとし、あなたはそれに許可を持たないからです)
そうすれば以下のように実行できます:
install SOAP::Lite
その後、スクリプトには以下のように追加する必要があります:
use lib '/your/home/directory/lib';
'use SOAP::Lite;'の前のどこかで。これで終わりです。
MacOSのためのコンパイルされたXML::Parserがここにあります:http://www.perl.com/CPAN-local/authors/id/A/AS/ASANDSTRM/XML-Parser-2.27-bin-1-MacOS.tgz
SOAP::Lite for Unix やSOAP::lite for Win32の最新バージョンは http://soaplite.com/ からダウンロードすることができます。SOAP::LiteはCPAN( http://search.cpan.org/search?dist=SOAP-Lite )からも利用することができます。コメント、提案、バグレポートそして文句はメールを作者(paulclinger@yahoo.com)へ書くことは歓迎されます。
SOAP Keith BrownによるSOAP/Perlライブラリ( http://www.develop.com/soap/ ) または ( http://search.cpan.org/search?dist=SOAP )
(原文のまま)
A lot of thanks to Tony Hong <thong@xmethods.net>, Petr Janata <petr.janata@i.cz>, Murray Nesbitt <murray@ActiveState.com>, Robert Barta <rho@bigpond.net.au>, Gisle Aas <gisle@ActiveState.com>, Carl K. Cunningham <cc@roberts.de>, Graham Glass <graham-glass@mindspring.com>, Chris Radcliff <chris@velocigen.com>, and many many others for provided help, feedback, support, patches and comments.
(原文のまま)
Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
(原文のまま)
Paul Kulchenko (paulclinger@yahoo.com)
ご意見、ご質問はこちらの掲示板で受け付けています。
またメールは河馬屋(Nifty)にお願いします。