SOAP是简单对象访问协议,它可看成是HTTP与XML的结合,其中XML部分是作为HTTP报文的实体主体部分。具体信息可以参考百度百科。

在iOS中使用SOAP,需要我们自己组装XML格式的字符串,当XML字符串比较长的时候会变得很麻烦。另外,我们在写XML格式的字符串时也要经常使用转义字符“\”。

为了编写我们的SOAP应用程序,先要找一个提供SOAP服务的网站,这里用的是http://www.webxml.com.cn,这是一个国内的提供Web服务的网站,很有意思。我们用到的是提供手机归属地查询的服务,具体网站是http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?op=getMobileCodeInfo。用浏览器打开这个网站,如下图:

若在mobileCode输入手机号码,userID不输入,点击调用,则结果如下:

这个结果呢不大准确,因为我输入的号码是动感地带的。但不影响本文主题。

看看刚才那个网页的内容,注意到SOAP 1.2标签下的内容:

POST /WebServices/MobileCodeWS.asmx HTTP/1.1
Host: webservice.webxml.com.cn
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length <?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<getMobileCodeInfo xmlns="http://WebXml.com.cn/">
<mobileCode>string</mobileCode>
<userID>string</userID>
</getMobileCodeInfo>
</soap12:Body>
</soap12:Envelope>

上面的这段文本就是使用SOAP 1.2的请求报文格式,就是一个HTTP请求报文,注意空行上面的那些内容中的请求行与各首部行的每个字段名,在下面的示例中会用到。这个HTTP请求报文的实体主体部分是XML格式的一段文本,注意Body标签之间的内容。

服务器的响应报文格式如下:

HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length <?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<getMobileCodeInfoResponse xmlns="http://WebXml.com.cn/">
<getMobileCodeInfoResult>string</getMobileCodeInfoResult>
</getMobileCodeInfoResponse>
</soap12:Body>
</soap12:Envelope>

我们要用到的只有getMobileCodeInfoResult这个标签。

这次的例子是实现通过SOAP服务查询手机号码归属地、运行商等信息。PS:用的Xcode 4.4.1。

1、运行Xcode 4.4.1,新建一个Single View Application,名称为SOAP Test:

2、界面设计:打开ViewController.xib,设计界面如下所示:

在文本输入框的Attribute Inspector中设置其Keyboard属性为Number Pad。

3、之后向ViewController.h中,为文本输入框创建OutLet映射,名称为:phoneNumber;为“查询”按钮创建Action映射,事件类型为Touch Up Inside,名称为:doQuery。建立映射的方法就是打开Assistant Editor,选中某一控件,按住Ctrl,拖向ViewController.h,可以参考前面的文章。

4、在ViewController.h中添加代码:

4.1 在@interface那行最后添加代码

<NSXMLParserDelegate,  NSURLConnectionDelegate>

使ViewController遵守这两个协议。前者用来解析XML,后者用于网络连接。

4.2 在@end之前添加代码

@property (strong, nonatomic) NSMutableData *webData;
@property (strong, nonatomic) NSMutableString *soapResults;
@property (strong, nonatomic) NSXMLParser *xmlParser;
@property (nonatomic) BOOL elementFound;
@property (strong, nonatomic) NSString *matchingElement;
@property (strong, nonatomic) NSURLConnection *conn;

5、在ViewController.m中添加代码:

5.1 在@implementation之后添加代码

@synthesize webData;
@synthesize soapResults;
@synthesize xmlParser;
@synthesize elementFound;
@synthesize matchingElement;
@synthesize conn;

5.2 实现doQuery方法

// 开始查询
- (IBAction)doQuery:(id)sender {
NSString *number = phoneNumber.text; // 设置我们之后解析XML时用的关键字,与响应报文中Body标签之间的getMobileCodeInfoResult标签对应
matchingElement = @"getMobileCodeInfoResult";
// 创建SOAP消息,内容格式就是网站上提示的请求报文的实体主体部分
NSString *soapMsg = [NSString stringWithFormat:
@"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<soap12:Envelope "
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
"xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">"
"<soap12:Body>"
"<getMobileCodeInfo xmlns=\"http://WebXml.com.cn/\">"
"<mobileCode>%@</mobileCode>"
"<userID>%@</userID>"
"</getMobileCodeInfo>"
"</soap12:Body>"
"</soap12:Envelope>", number, @""]; // 将这个XML字符串打印出来
NSLog(@"%@", soapMsg);
// 创建URL,内容是前面的请求报文报文中第二行主机地址加上第一行URL字段
NSURL *url = [NSURL URLWithString: @"http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx"];
// 根据上面的URL创建一个请求
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMsg length]];
// 添加请求的详细信息,与请求报文前半部分的各字段对应
[req addValue:@"application/soap+xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[req addValue:msgLength forHTTPHeaderField:@"Content-Length"];
// 设置请求行方法为POST,与请求报文第一行对应
[req setHTTPMethod:@"POST"];
// 将SOAP消息加到请求中
[req setHTTPBody: [soapMsg dataUsingEncoding:NSUTF8StringEncoding]];
// 创建连接
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn) {
webData = [NSMutableData data];
}
}

5.3 在@end之前添加代码

#pragma mark -
#pragma mark URL Connection Data Delegate Methods // 刚开始接受响应时调用
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *) response{
[webData setLength: 0];
} // 每接收到一部分数据就追加到webData中
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *) data {
[webData appendData:data];
} // 出现错误时
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *) error {
conn = nil;
webData = nil;
} // 完成接收数据时调用
-(void) connectionDidFinishLoading:(NSURLConnection *) connection {
NSString *theXML = [[NSString alloc] initWithBytes:[webData mutableBytes]
length:[webData length]
encoding:NSUTF8StringEncoding]; // 打印出得到的XML
NSLog(@"%@", theXML);
// 使用NSXMLParser解析出我们想要的结果
xmlParser = [[NSXMLParser alloc] initWithData: webData];
[xmlParser setDelegate: self];
[xmlParser setShouldResolveExternalEntities: YES];
[xmlParser parse];
}

5.4 在@end之前添加代码

#pragma mark -
#pragma mark XML Parser Delegate Methods // 开始解析一个元素名
-(void) parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *) attributeDict {
if ([elementName isEqualToString:matchingElement]) {
if (!soapResults) {
soapResults = [[NSMutableString alloc] init];
}
elementFound = YES;
}
} // 追加找到的元素值,一个元素值可能要分几次追加
-(void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string {
if (elementFound) {
[soapResults appendString: string];
}
} // 结束解析这个元素名
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:matchingElement]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"手机号码信息"
message:[NSString stringWithFormat:@"%@", soapResults]
delegate:self
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alert show];
elementFound = FALSE;
// 强制放弃解析
[xmlParser abortParsing];
}
} // 解析整个文件结束后
- (void)parserDidEndDocument:(NSXMLParser *)parser {
if (soapResults) {
soapResults = nil;
}
} // 出错时,例如强制结束解析
- (void) parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
if (soapResults) {
soapResults = nil;
}
}

6、运行

  

其中,输入号码时单击查询,打印出的响应XML如下:

<?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>
<getMobileCodeInfoResponse xmlns="http://WebXml.com.cn/">
<getMobileCodeInfoResult>151898XXXXX:江苏 南京 江苏移动全球通卡
</getMobileCodeInfoResult>
</getMobileCodeInfoResponse>
</soap:Body>
</soap:Envelope>

上面的XML进行了缩进处理,实际上打印出来的是一行。

完整代码:http://www.oschina.net/code/snippet_164134_13248

转:http://my.oschina.net/plumsoft/blog/75277

iOS开发25:使用SOAP访问Web服务的更多相关文章

  1. Android开发9:网络访问&Web服务开发

    前言 啦啦啦各位小伙伴们好~ 一起进入我们今天的主题.今天我们将和大家学习网络访问和Web服务开发的相关知识,一起学习熟练使用 HttpURLConnection 访问 WebService,熟悉使用 ...

  2. EJB_开发EJB容器模型的WEB服务

    开发EJB容器模型的WEB服务 WEB服务 Web服务也是一种分布式技术,它与EJB最大的不同是,Web服务属于行业规范,可以跨平台及语言.而EJB属于Java平台的规范,尽管理论上可以跨平台,但实现 ...

  3. Reporting Service编程----访问Web服务

    将报表服务器 Web 服务的引用添加到项目中后,下一步是创建 Web 服务代理类的实例. 然后,您可以通过调用代理类中的方法来访问 Web 服务的方法. 当你的应用程序调用这些方法时,代理类生成的代码 ...

  4. 25.C# 异步调用Web服务

    1.创建Web服务 1.1VS新建ASP.Net空Web应用程序 1.2添加Web服务新建项 1.3添加GetWeather方法和相关类 using System; using System.Coll ...

  5. iOS开发25个性能调优技巧

    1. 用ARC管理内存 ARC(Automatic Reference Counting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露.它自动为 ...

  6. 允许浏览器跨域访问web服务端的解决方案

    今天和同事探讨了前后端如何真正实现隔离开发的问题,如果前端单独作为服务发布,势必会涉及到无法直接调用后端的接口的问题,因为浏览器是不允许跨域提交请求的. 所谓跨域访问,就是在浏览器窗口,和某个服务端通 ...

  7. php 允许浏览器跨域访问web服务端的解决方案

    今天和同事探讨了前后端如何真正实现隔离开发的问题,如果前端单独作为服务发布,势必会涉及到无法直接调用后端的接口的问题,因为浏览器是不允许跨域提交请求的. 所谓跨域访问,就是在浏览器窗口,和某个服务端通 ...

  8. iOS开发--系统通讯录的访问与添加联系人

    公司项目有访问通讯录的需求,所以开始了探索之路.从开始的一无所知,到知识的渐渐清晰.这一切要感谢广大无私分享的 “coder”,注:我是尊称的语气! 苹果提供了访问系统通讯录的框架,以便开发者对系统通 ...

  9. 用python开发了一个简单apache web服务端范例,在win10 + apache2.4.9 + python3.5 测试成功

    #!D:\Programs\Python\Python35-32\python.exe import cgi def htmlTop():     print("Content-type: ...

随机推荐

  1. 用原生js实现ajax

    // 通过createXHR()函数创建一个XHR对象 function createXHR() { if(window.XMLHttpRequest) { // IE7.Firefox.Opera. ...

  2. 【OpenCV for Android】Android Studio集成OpenCV

    准备工作 1.下载安装Android Studio(过程略). 2.下载Android OpenCV:https://opencv.org/releases.html,找到Android pack点击 ...

  3. js里size和length的区别

    length: length是js的原生方法,用于获取元素的个数和对象的长度 var length = $(obj).length; size(): size()属于方法,只能作用于对象上,获取元素的 ...

  4. php生成随机数

    生成1-10之间的随机数,不重复. 方法一:用shuffle函数. <?php $arr=range(1,10); shuffle($arr); foreach($arr as $values) ...

  5. 后缀自动机(SAM)速成手册!

    正好写这个博客和我的某个别的需求重合了...我就来讲一讲SAM啦qwq 后缀自动机,也就是SAM,是一种极其有用的处理字符串的数据结构,可以用于处理几乎任何有关于子串的问题,但以学起来异常困难著称(在 ...

  6. Spark streaming的执行流程

    http://www.cnblogs.com/shenh062326/p/3946341.html  其实流程是从这里转载下来的,我只是在流程叙述中做了一下的标注. 当然为了自己能记住的更清楚,我没有 ...

  7.  sublime text3快速生成html头部信息(转)

    sublime text3快速生成html头部信息  https://blog.csdn.net/sunshinegirl_7/article/details/49802579 经常见别人创建新的ht ...

  8. 001.NFS简介

    一 简介 NFS 是Network File System的缩写,即网络文件系统.一种使用于分散式文件系统的协定,由Sun公司开发,于1984年向外公布.功能是通过网络让不同的机器.不同的操作系统能够 ...

  9. hashCode()方法与equals()方法

    摘自别人的评论:http://blog.csdn.net/fhm727/article/details/5221792 当向集合Set中增加对象时,首先集合计算要增加对象的hashCode码,根据该值 ...

  10. Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C. Destroying Array 带权并查集

    C. Destroying Array 题目连接: http://codeforces.com/contest/722/problem/C Description You are given an a ...