Edit Into A SOAP Envelope

An application that depends largely on the work of the SOAP web service asp.net much in the simulator and then hit with a shock that CoreServices library function that does not contain all web services available on the iPhone. I keep hoping that this feature was recently added.

All my code depends on receiving the object NSArray and NSDictionary key, and do not want to edit into a SOAP envelope to create the missing features emulate approval of the request is REST. I can only method used to make web service call and the same code base. I thought I share to all in this together.

Fortunately asp.net and is compatible with the REST style requests (I am not aware of this earlier today), so no changes are needed in the web server.

To demonstrate here the call to a simple method called “SayHello”. You pass in name and it returns a single item called “string” that contains “Hello [yourname]“. The code will work with more complex objects with child properties as well, and return them as NSDictionary and NSArray objects, but for simplicity I’m using “SayHello”.

Code :

NSArray *keys = [NSArray arrayWithObjects:@"userName", nil];
NSArray *objects = [NSArray arrayWithObjects:@"jeremy", nil];
NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSDictionary *wsResponse=[WebServices callRestService:@"SayHello" :params];

NSString *responseString=[wsResponse objectForKey:@"string"];

 

callRestService is a helper method I created in a class called Webservices. This code was exactly the same before except the helper method was called callSoapService.

WebServices.m contains two methods. getRestUrl just appends all the method parameters into a url to make the REST request. callRestService uses the build-in NSXMLParser class to retrieve the xml and sends it to a custom class called XmlParser to handle the callbacks and create the NSDictionary result,

WebServices.m

Code:

+(id)callRestService: (NSString *) methodName : (NSDictionary *) params
{
        NSURL *url=[WebServices getRestUrl: methodName : params];
        XmlParser *xmlParser = [[XmlParser alloc] init];

        NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
        [parser setDelegate:xmlParser];
        [parser setShouldProcessNamespaces:NO];
        [parser setShouldReportNamespacePrefixes:NO];
        [parser setShouldResolveExternalEntities:NO];
        [parser parse];
        [parser release];
        return xmlParser.result;
}

+(NSURL *)getRestUrl: (NSString *) methodName : (NSDictionary *) params
{
        NSString *url=@"http://services.mywebsite.com/mywebservice.asmx/";
        url=[url stringByAppendingString:methodName];

        BOOL firstKey=TRUE;
        for (NSString *key in params)
        {
               NSString *value=[params objectForKey:key];
               if (firstKey) url=[url stringByAppendingString:@"?"]; else url=[url stringByAppendingString:@"&"];
               url=[url stringByAppendingString:key];
               url=[url stringByAppendingString:@"="];
               url=[url stringByAppendingString:value];
               firstKey=FALSE;
        }
        return [NSURL URLWithString:url];
}

 

The final step is to create the XmlParser handler. This class keeps track of each open and close tag to build an object tree containing NSMutableArray NSMutableDictionary and NSString objects.

XmlParser.h

Code:

 

#import <Foundation/Foundation.h>


@interface XmlParser : NSObject {
        NSMutableDictionary *result;
        NSString *currentElementName;
        NSString *currentElementValue;
        NSMutableArray *parentArray;
}

@property (nonatomic, retain) NSMutableDictionary *result;
@property (nonatomic, retain) NSString *currentElementName;
@property (nonatomic, retain) NSString *currentElementValue;
@property (nonatomic, retain) NSMutableArray *parentArray;


- (void)parserDidStartDocument:(NSXMLParser *)parser;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;

@end

XmlParser.m

Code:

#import "XmlParser.h"


@implementation XmlParser
@synthesize result;
@synthesize currentElementName;
@synthesize currentElementValue;
@synthesize parentArray;


- (void)parserDidStartDocument:(NSXMLParser *)parser
{
        result=[[NSMutableDictionary alloc] init];
        parentArray=[[NSMutableArray alloc] init];
        [parentArray addObject:result];
        currentElementName=@"";
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
        if (qName) {
               elementName = qName;
        }
        currentElementValue=@"";
        if (currentElementName!=@"")
        {
               id newParent=NULL;
               if ([currentElementName isLike:@"*Array*"])
               {
                       newParent=[[NSMutableArray alloc] init];
               } else {
                       newParent=[[NSMutableDictionary alloc] init];
               }
               [parentArray addObject:newParent];
        }
        currentElementName=elementName;
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
        if (qName) {
               elementName = qName;
        }

        if (currentElementName==@"")
        {
               //We're adding a container with children.  Add it to the parent and remove this item fromt he parentArray
               int currentIndex=[parentArray count]-1;
               int parentIndex=currentIndex - 1;
               id currentChild=[parentArray objectAtIndex:currentIndex];
               id currentParent=[parentArray objectAtIndex:parentIndex];

               if ([currentParent isKindOfClass:[NSMutableArray class]])
               {
                       [currentParent addObject:currentChild];
               } else {
                       [currentParent setObject:currentChild forKey:elementName];
               }

               [parentArray removeObjectAtIndex:currentIndex];
        } else {
               //We're adding a simple type element
               int currentIndex=[parentArray count]-1;
               id currentParent=[parentArray objectAtIndex:currentIndex];
               if ([currentParent isKindOfClass:[NSMutableArray class]])
               {
                       [currentParent addObject:currentElementValue];
               } else {
                       [currentParent setObject:currentElementValue forKey:currentElementName];
               }
        }
        currentElementName=@"";
}


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
        currentElementValue=string;
}

@end

 

 

That’s it. I’m sure it’s not the cleanest code (This is my very first XCode app) and there may be a better way of doing this, but it saved me from having to rewrite all my code that was retrieving data from SOAP services. I’ve seen tons of other people with the same problem and no solutions so far.

Comments are closed.