Consuming XML Web Services in iPhone Applications

前端之家收集整理的这篇文章主要介绍了Consuming XML Web Services in iPhone Applications前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
Consuming XML Web Services in iPhone Applications
@H_403_5@
Find out the varIoUs ways you can call web services and parseresponses from your iPhone applications to give your applications ahuge range of data sources.
by Wei-Meng Lee

Consuming<wbr></p>XML<wbr>Web<wbr>Services<wbr>in<wbr>iPhone<wbr>Applicationsommunicating with the outside world isone of the ways to make your iPhone applications interesting anduseful. This is especially true today where they are so many webservices that provide so much useful functionality. However,consuming web services in iPhone is not for the faint-of-heart.Unlike other development tools (such as Microsoft Visual Studio),Xcode does not have built-in tools that make consuming web serviceseasy. Everything must be done by hand and you need to know how toform the relevant XML messages to send to the web services and thenparse the returning XML result.

This article will give you a good understanding of how tocommunicate with XML web services from within your iPhoneapplication,and the examples will provide a solid foundation forconsuming other web services in your own projects.

Consuming Web Services

Consuming<wbr></p>XML<wbr>Web<wbr>Services<wbr>in<wbr>iPhone<wbr>Applications

Figure 1.IPToCountry Web Service:This web service exposes two webmethods.

Before beginning an Xcode project to consume a web service,examining a real web service to see the different ways you canconsume is worthwhile. My favorite example is to use an ASMX XMLweb service created using .NET. For discussion purposes,here's alook at a web service calledIPToCountry,which lets you supply an IP address and returns the country towhich the IP address belongs.

TheIPToCountrywebservice is locatedathttp://www.ecubicle.net/iptocountry.asmx.If you use Safari to load this URL,you'll see that it exposes twoweb methods as shown inFigure1.

As an example,theFindCountryAsXMLreturnsthe result (the country) as an XML string. Clicking theFindCountryAsXML link reveals the page showninFigure2.

Consuming<wbr></p>XML<wbr>Web<wbr>Services<wbr>in<wbr>iPhone<wbr>Applications

Figure 2.FindCountryAsXml Service:Testing the webservice through a browser interface shows the XML packets exchangedbetween the client and the server.

The important parts are the sections following the Test sectionof the page. They detail the varIoUs ways in which you can consumethe web service. In the .NET world,accessing the web service is apretty straightforward affair—Visual Studio provides a built-intool that automatically creates a web proxy service object for theweb service when you download the WSDL document. For iPhonedevelopment,you need to get your hands dirty,so it's far moreimportant to understand the underlying mechanics of consuming webservices.

Using SOAP 1.1

One way to consume this web service is to use SOAP (SimpleObject Access Protocol). When using SOAP,you use theHTTPPOSTmethod to send a request to theweb service,as shown in the following example:

POST /iptocountry.asmx HTTP/1.1
Host: www.ecubicle.net
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.ecubicle.net/webservices/FindCountryAsXml"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <FindCountryAsXml xmlns="http://www.ecubicle.net/webservices/">
      <V4IPAddress>string</V4IPAddress>
    </FindCountryAsXml>
  </soap:Body>
</soap:Envelope>

The parts of the code in bold are the placeholders where youneed to substitute the actual values. A couple of important thingsto note from the above:

  • The URL for the web serviceishttp://www.ecubicle.net/iptocountry.asmx.
  • The URL fortheSOAPActionattributeishttp://www.ecubicle.net/webservices/FindCountryAsXml.
  • TheContent-Typeforthe request istext/xml;charset=utf-8.
  • The HTTP method isPOST.
  • The SOAP request is shown below:
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
      <soap:Body>
        <FindCountryAsXml xmlns="http://www.ecubicle.net/webservices/">
          <V4IPAddress>string</V4IPAddress>
        </FindCountryAsXml>
      </soap:Body>
    </soap:Envelope>
  • TheContent-Lengthofthe SOAP request is the total number of characters in the completeSOAP request.

The web service will return a response formatted as follows:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <FindCountryAsXmlResponse 
      xmlns="http://www.ecubicle.net/webservices/">
      <FindCountryAsXmlResult>xml result</FindCountryAsXmlResult>
    </FindCountryAsXmlResponse>
  </soap:Body>
</soap:Envelope>

For a real request,the result (the country) will be enclosedwithin the block of XML code (the bold placeholder in the precedingexample). You would need to extract it from the XML result.




Using SOAP 1.2

Using SOAP 1.2 is very similar to using SOAP 1.1. Here's asample request:

POST /iptocountry.asmx HTTP/1.1
Host: www.ecubicle.net
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>
    <FindCountryAsXml xmlns="http://www.ecubicle.net/webservices/">
      <V4IPAddress>string</V4IPAddress>
    </FindCountryAsXml>
  </soap12:Body>
</soap12:Envelope>

The SOAP response for SOAP 1.2 would be:

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>
    <FindCountryAsXmlResponse 
       xmlns="http://www.ecubicle.net/webservices/">
      <FindCountryAsXmlResult>xml result</FindCountryAsXmlResult>
    </FindCountryAsXmlResponse>
  </soap12:Body>
</soap12:Envelope>

Using HTTPGET

For many web services,if you do not want to use SOAP,you canoften use the simplerHTTPGETmethod. Here'sthe format to sendaGETrequest:

GET /iptocountry.asmx/FindCountryAsXml?V4IPAddress=string HTTP/1.1
Host: www.ecubicle.net
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

Take note of the following:

  • The URL for the web serviceishttp://www.ecubicle.net/iptocountry.asmx/FindCountryAsXml?V4IPAddress=string.
  • TheContent-Typeforthe request istext/xml;charset=utf-8.
  • TheContent-Lengthforthe request is0,because you don't needto send anything separately (everything gets sent through the querystring).
  • The HTTP method isGET.

The web service will return its result in the followingformat:

<?xml version="1.0"?>
xml result

Using HTTPPOST

In addition to using HTTPGET,you canalso use HTTPPOST. Here's the format forsending the request:

POST /iptocountry.asmx/FindCountryAsXml HTTP/1.1
Host: www.ecubicle.net
Content-Type: application/x-www-form-urlencoded
Content-Length: length
V4IPAddress=string

Take note of the following:

  • The URL for the web serviceishttp://www.ecubicle.net/iptocountry.asmx/FindCountryAsXml.
  • TheContent-Typeforthe requestisapplication/x-www-form-urlencoded.
  • TheContent-Lengthforthe request is the lengthofV4IPAddress=string.
  • The HTTP method isPOST.

The web service returns the following result:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0"?>
xml result




Consuming Web Services in iPhone Applications

With all the background explained,you can now tackle theexciting task of consuming a web service in your iPhoneapplication! First,you need to learn to communicate with the webservice using SOAP.

Using Xcode,create a View-based Application project and nameitWebServices. Double-clicktheWebServicesViewController.xibfileto open it in Interface Builder. Double-click on the View item andpopulate it with the views listed below and showninFigure3:

  • Label
  • Text Field
  • Round Rect Button
  • Activity Indicator

Consuming<wbr></p>XML<wbr>Web<wbr>Services<wbr>in<wbr>iPhone<wbr>Applications

Figure 3.Building a Web Service Client:Populatethe View window with the varIoUs views shown here.

Back in Xcode,edittheWebServicesViewController.hfileand add the statements shown in bold in the following code:

#import <UIKit/UIKit.h>
@interface WebServicesViewController : UIViewController {
    //---outlets--- IBOutlet UITextField *ipAddress; IBOutlet UIActivityIndicatorView *activityIndicator; //---web service access--- NSMutableData *webData; NSMutableString *soapResults; NSURLConnection *conn;
}
@property (nonatomic,retain) UITextField *ipAddress; @property (nonatomic,retain) UIActivityIndicatorView *activityIndicator; - (IBAction)buttonClicked:(id)sender;
@end

Save the file and return to Interface Builder,where you need toperform the following actions:

  • Control-click on the File’s Owner item and drag it over theText Field view. SelectipAddress.
  • Control-click on the File’s Owner item and drag it over theActivity Indicator view.SelectactivityIndicator.
  • Control-click the Rounded Rect Button view and drag it over theFile’s Owner item. SelectthebuttonClicked:action.

Consuming<wbr></p>XML<wbr>Web<wbr>Services<wbr>in<wbr>iPhone<wbr>Applications

Figure 4.Completed Connections:The figure shows the outletconnections and actions for the File’s Owner item.

If you right-click on the File’s Owner item now,you should seethe connections as shown inFigure4.

IntheWebServicesViewController.mfile,first create the setters and getters for the Text Field andActivity Indicator properties:

import "WebServicesViewController.h"
@implementation WebServicesViewController
@synthesize ipAddress; @synthesize activityIndicator;

Next,definethebuttonClicked:method(seeListing1),which will formulate the SOAP request packet and send itover to the web service.

Let’s spend some time examining what you just did by adding thecode inListing 1.First,you create the SOAP request packet:

NSString *soapMsg = 
        [NSString stringWithFormat:
            @"<?xml version="1.0" encoding="utf-8"?>"
             "<soap:Envelope 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
              xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">"
             "<soap:Body>"
             "<FindCountryAsXml 
               xmlns="http://www.ecubicle.net/webservices/">"
             "<V4IPAddress>%@</V4IPAddress>"
             "</FindCountryAsXml>"
             "</soap:Body>"
             "</soap:Envelope>",ipAddress.text
        ];

Next,you create a URL load request object using instances ofthe NSMutableURLRequest and NSURL objects:

NSURL *url = [NSURL URLWithString: 
      @"http://www.ecubicle.net/iptocountry.asmx"];
    NSMutableURLRequest *req = 
      [NSMutableURLRequest requestWithURL:url];

You then populate the request object with the varIoUs headers,suchasContent-Type,SOAPAction,andContent-Length. You also set the HTTPmethod and HTTP body:

NSString *msgLength = 
      [NSString stringWithFormat:@"%d",[soapMsg length]];
    [req addValue:@"text/xml; charset=utf-8"  
      forHTTPHeaderField:@"Content-Type"];
    [req addValue:@"http://www.ecubicle.net/webservices/FindCountryAsXml" 
      forHTTPHeaderField:@"SOAPAction"];
    [req addValue:msgLength 
      forHTTPHeaderField:@"Content-Length"];
    [req setHTTPMethod:@"POST"];
    [req setHTTPBody: [soapMsg dataUsingEncoding:NSUTF8StringEncoding]];

Before you make the actual request to the web service,you getthe Activity Indicator view to start animating,thus providing avisual Feedback to the user that the application is waiting for aresponse from the web service:

[activityIndicator startAnimating];

To establish the connection with the web service,you use theNSURLConnection class together with the request object justcreated:

conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
   if (conn) {
      webData = [[NSMutableData data] retain];
}

The NSURLConnection object will now send the request to the webservice,and will asynchronously call varIoUs methods (which youwill define next) as it receives responses from the web service.Thedatamethod of theNSMutableData class returns an empty data object that represents awrapper for byte buffers,which you will use to receive incomingdata from the web service.

When data starts streaming in from the web service,theconnection:didReceiveResponse:methodwill be called,which you need to implement here:

-(void) connection:(NSURLConnection *) connection 
didReceiveResponse:(NSURLResponse *) response {
   [webData setLength: 0];
}

Note that the preceding code initializes the lengthofwebDatato0.As the data progressively comes in from the web service,theconnection:didReceiveData:method willbe called repeatedly. You use the method to append the datareceived tothewebDataobject:

-(void) connection:(NSURLConnection *) connection 
didReceiveData:(NSData *) data {
   [webData appendData:data];
}

If there is an error during the transmission,theconnection:didFailWithError:methodwill be called:

-(void) connection:(NSURLConnection *) connection 
didFailWithError:(NSError *) error {
[webData release];
    [connection release];
}

When the connection has finished and succeeded in downloadingthe response,theconnectionDidFinishLoading:methodwill be called:

-(void) connectionDidFinishLoading:(NSURLConnection *) connection {
    NSLog(@"DONE. Received Bytes: %d",[webData length]);
    NSString *theXML = [[NSString alloc] 
                        initWithBytes: [webData mutableBytes] 
                        length:[webData length] 
                        encoding:NSUTF8StringEncoding];
    //---shows the XML---
    NSLog(theXML);
    [theXML release];    
    [activityIndicator stopAnimating];    
    
    [connection release];
    [webData release];
}

For this example,you simply print the XML response receivedfrom the web service to the Debugger Console window and then stopthe Activity Indicator view from animating.

Finally,release all the properties and objects inthedeallocmethod:

- (void)dealloc {    
    [ipAddress release]; [activityIndicator release]; [xmlParser release]; [soapResults release];
    [super dealloc];
}

That’s it! Press Command-R to test the application on the iPhoneSimulator. Enter the IPaddress34.5.6.7in theText Field,and then tap the Find Country button. In Xcode,pressShift-Command-R to open the Debugger Console window. You'll seethat the following request was sent to the web service:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <FindCountryAsXml xmlns="http://www.ecubicle.net/webservices/">
         <V4IPAddress>34.5.6.7</V4IPAddress>
      </FindCountryAsXml>
   </soap:Body>
</soap:Envelope>

The web service SOAP response contains "United States."

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <FindCountryAsXmlResponse 
         xmlns="http://www.ecubicle.net/webservices/">
         <FindCountryAsXmlResult>
            <IPCountryService xmlns="">
               <Country>United States</Country>
            </IPCountryService>
         </FindCountryAsXmlResult>
      </FindCountryAsXmlResponse>
   </soap:Body>
</soap:Envelope>

The response from the web service indicates that you havemanaged to communicate with the web service. The problem now is howto parse the XML to extract the relevant result that you want. Inthis case,the result you want is encapsulated inthe<Country>element.The last section of this article shows how to parse the XMLresponse,but for now,let’s see what you should do if you want touse the HTTP GET and HTTP POST methods,as opposed to using theSOAP method to talk to the web service.




Using HTTP POST with Web Services

To talk to a web service using HTTP POST,you just need tomodifythebuttonClicked:method,like this:

- (IBAction)buttonClicked:(id)sender {
    NSString *postString = [NSString stringWithFormat:@"V4IPAddress=%@",ipAddress.text];
    NSLog(postString);
    
    NSURL *url = [NSURL URLWithString: @"http:// www.ecubicle.net/iptocountry.asmx/FindCountryAsXml"]; NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; NSString *msgLength = [NSString stringWithFormat:@"%d",[postString length]]; [req addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[req addValue:msgLength forHTTPHeaderField:@"Content-Length"];
    [req setHTTPMethod:@"POST"];
    [req setHTTPBody: [postString 
       dataUsingEncoding:NSUTF8StringEncoding]];
    
    [activityIndicator startAnimating];
    
    conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
    if (conn) {
        webData = [[NSMutableData data] retain];
    }    
}

Basically,you do away with forming the SOAP message and simplypost a single string to the web service,suchasV4IPAddress=34.5.6.7. When you run themodified application and watch the Debugger Console,you should seea response like this:

<?xml version="1.0" encoding="utf-8"?>
<IPCountryService>
    <Country>United States</Country>
</IPCountryService>

Using HTTPGETwithWeb Services

Using HTTPGETtotalk to a web service is even simpler,because you pass all therequest information via the query string. The following shows themodifiedbuttonClicked:method to accessthe web service using theHTTPGETmethod:

- (IBAction)buttonClicked:(id)sender {
NSString *queryString = [NSString stringWithFormat: @"http://www.ecubicle.net/iptocountry.asmx/" + "FindCountryAsXml?V4IPAddress=%@",ipAddress.text]; NSURL *url = [NSURL URLWithString:queryString]; NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; [req addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [req addValue:0 forHTTPHeaderField:@"Content-Length"]; [req setHTTPMethod:@"GET"];
[activityIndicator startAnimating];
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn) {
webData = [[NSMutableData data] retain];
}
}

Like theHTTPPOSTmethod,theresponse in the Debugger Console when you run the modifiedapplication should look like this:

<?xml version="1.0" encoding="utf-8"?>
<IPCountryService>
    <Country>United States</Country>
</IPCountryService>

Parsing XML Responses

At this point,you're familiar with the varIoUs ways to call aweb service,now you need to learn how to parse the XML response.The iPhone SDK includes an NSXMLParser object that you can use toparse an XML file. The NSXMLParser class is an implementation ofthe Simple API for XML (SAX),which parses an XML document (orstring) serially.

An NSXMLParser object reads an XML document and scans it frombeginning to end. As it encounters the varIoUs items in thedocument (such as elements,attributes,comments,and so on),itnotifies its delegates so that you can take appropriate action,such as extracting the value of an element.

To parse the response from the web service,add the followingstatements totheWebServicesViewController.hfile:

#import <UIKit/UIKit.h>
@interface WebServicesViewController : UIViewController {
    //---outlets---
    IBOutlet UITextField *ipAddress;
    IBOutlet UIActivityIndicatorView *activityIndicator;
    
    //---web service access---
    NSMutableData *webData;
    NSMutableString *soapResults;
    NSURLConnection *conn;
    //---xml parsing--- NSXMLParser *xmlParser; BOOL *elementFound;        
}
@property (nonatomic,retain) UITextField *ipAddress;
@property (nonatomic,retain) UIActivityIndicatorView *activityIndicator;
- (IBAction)buttonClicked:(id)sender;
@end

IntheWebServicesViewController.mfile,add the statements shown below in bold totheconnectionDidFinishLoading:method:

-(void) connectionDidFinishLoading:(NSURLConnection *) connection {
    NSLog(@"DONE. Received Bytes: %d",[webData length]);
    NSString *theXML = [[NSString alloc] 
                        initWithBytes: [webData mutableBytes] 
                        length:[webData length] 
                        encoding:NSUTF8StringEncoding];
    //---shows the XML---
    NSLog(theXML);
[theXML release];    
    [activityIndicator stopAnimating];    
    if (xmlParser) { [xmlParser release]; } xmlParser = [[NSXMLParser alloc] initWithData: webData]; [xmlParser setDelegate: self]; [xmlParser setShouldResolveExternalEntities:YES]; [xmlParser parse];
    
    [connection release];
[webData release];
}

You create an instance of the NSXMLParser class and theninitialize it with the response returned by the web service. As theparser encounters the varIoUs items in the XML document,it willfire off several methods,which you need to define next.

The first method to implementisparser:didStartElement:namespaceURI:qualifiedName:attributes:,which is fired when the start tag of an element is found:

//---when the start of an element is found---
-(void) parser:(NSXMLParser *) parser 
   didStartElement:(NSString *) elementName 
namespaceURI:(NSString *) namespaceURI 
qualifiedName:(NSString *) qName
attributes:(NSDictionary *) attributeDict {
    
    if( [elementName isEqualToString:@"Country"])
    {
        if (!soapResults)
        {
            soapResults = [[NSMutableString alloc] init];
        }
        elementFound = YES;
    }
}

The preceding code checks to see whether the current tagis<Country>.If it is,you set the BooleanvariableelementFoundtoYES.

The next method to implementisparser:foundCharacters:,which gets fired when the parser finds the text of an element:

-(void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string
{
    if (elementFound)
    {
        [soapResults appendString: string];
    }
}

Here,if the last tag foundwas<Country>,you want to extract the value oftheCountryelementintosoapResults.

Finally,when the parser encounters the end of an element,itfirestheparser:didEndElement:namespaceURI:qualifiedName:method:

//---when the end of element is found---
-(void)parser:(NSXMLParser *)parser 
    didEndElement:(NSString *)elementName 
    namespaceURI:(NSString *)namespaceURI 
    qualifiedName:(NSString *)qName
{
    if ([elementName isEqualToString:@"Country"])
    {
        //---displays the country---
        NSLog(soapResults);        
        UIAlertView *alert = [[UIAlertView alloc] 
          initWithTitle:@"Country found!"

Consuming<wbr></p>XML<wbr>Web<wbr>Services<wbr>in<wbr>iPhone<wbr>Applications

Figure 5.Country Found:The completed exampleapplication displays the country name after parsing the XMLresult.
message:soapResults 
        delegate:self  
        cancelButtonTitle:@"OK" 
        otherButtonTitles:nil];
        [alert show];
        [alert release];
        [soapResults setString:@""];
        elementFound = FALSE; 
    }
}

Here,you simply look for theclosing</Country>tag;when you find it you know that the value of the Country element hasbeen correctly extracted. You then print out the value using aUIAlertView object.

Finally! You can now test the application on the iPhoneSimulator by pressing Command-R. Enter an IP address and click theFind Country button.Figure5shows you the result!

At this point,you've seen a working iPhone application thatillustrates the varIoUs ways you can consume a web service in youriPhone applications: SOAP,HTTPGET,andHTTPPOST. The example both calls a webservice and shows how to extract data from the XML-formattedresponse. Using web services (and being able to parse XML) in youriPhone applications can open up an entire world full of data toyour applications.

猜你在找的XML相关文章