Objective-CでXML Webサービスを使ってみる
調べてもまともに情報が出てこずに、いろいろ大変だったのでメモ。
ここを使わせてもらう。
準備
wsdl2objcをダウンロードする。ここのUsageInstructionsはまるで役に立たないので無視。
先のサービスのWSDLを取得して*1、objcのソースを出力しておく。
実装
Xcodeを起動してプロジェクトを新規作成。
[TARGETS]-[Build Phases]にlibxml2.2.dylibを追加。
[TARGETS]-[Build Settings]-[Header Search Paths]に"${SDKROOT}/usr/include/libxml2"を追加。
先に出力したソースを全部プロジェクトに取り込む。
importして、
#import "TempConvert.h"
実装して、
TempConvertSoap *soap = [TempConvert TempConvertSoap]; soap.logXMLInOut = YES; TempConvert_CelsiusToFahrenheit *p = [[TempConvert_CelsiusToFahrenheit alloc] init]; p.Celsius = @"30"; TempConvertSoapResponse *response = [soap CelsiusToFahrenheitUsingParameters:p]; NSLog(@"res:%@",response);
実行するものの、なにか問題が起きてる。
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <soap:Fault> <soap:Code> <soap:Value>soap:Sender</soap:Value> </soap:Code> <soap:Reason> <soap:Text xml:lang="en">Unable to handle request without a valid action parameter. Please supply a valid soap action.</soap:Text> </soap:Reason> <soap:Detail /> </soap:Fault> </soap:Body> </soap:Envelope>
この時点でさっぱりわからなくなったんだけど、実行例と比べてみると入力が微妙に異なる。
<?xml version="1.0"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:TempConvert="http://tempuri.org/" xsl:version="1.0"> <soap:Body> <CelsiusToFahrenheit xsi:type="TempConvert:CelsiusToFahrenheit"> <Celsius>30</Celsius> </CelsiusToFahrenheit> </soap:Body> </soap:Envelope>
WSDLから自動生成されたソースを修正。これ合ってるの?
// TempConvert.m // @implementation TempConvert_CelsiusToFahrenheit // - (xmlNodePtr)xmlNodeForDoc:(xmlDocPtr)doc elementName:(NSString *)elName // 266行目 // xmlSetNsProp(node, xsi, (const xmlChar*)"type", (const xmlChar*)"TempConvert:CelsiusToFahrenheit"); xmlNsPtr xmlns = xmlSearchNs(doc, root, (const xmlChar*)"xmlns"); xmlSetNsProp(node, xmlns, (const xmlChar*)"xmlns", (const xmlChar*)"http://tempuri.org/");
再度実行すると
TempConvertSoapResponse *response = [soap CelsiusToFahrenheitUsingParameters:p]; // NSLog(@"res:%@",response); // NSLog(@"body: %@",response.bodyParts); TempConvert_CelsiusToFahrenheitResponse *result = [response.bodyParts objectAtIndex:0]; NSLog(@"%@F",result.CelsiusToFahrenheitResult); // => 2013-10-04 23:09:50.059 xmlwebsvc-test[767:c303] 86F
通りました。
まとめ
SOAPのやりとりがめんどくさい。
HTTP Postでも呼び出せるならそっちの方がいいんじゃないかと思う。そこでRESTの登場ですよってことなのかな。
VisualStudioだとサービス参照追加するだけで済むのでらくちん。
var client = new TempConvert.TempConvertSoapClient("TempConvertSoap"); string fahrenheit = client.CelsiusToFahrenheit("30"); System.Diagnostics.Debug.WriteLine(string.Format("{0}F", fahrenheit)); // => 86F
だからこそ、裏側をなにも知らなかったんだな。