Parsing SOAP result using TouchXML in iOS SDK (iPad) - iphone

I'm working on an iPad project that is using functions in a WebService.
Handling webservice connection, data etc works find. But i'm not able to parse the result SOAP using TouchXML. Getting the nodes out of the xml always returns 0 length.
The output xml:
<?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> <LogOnResponse xmlns="http://coreservices.org/v1"> <LogOnResult> <Id>1c0e9ad0-a3be-4cd0-8f0d-0616a63a4e28</Id> <userId>2</userId> <user> <ID>2 <Name>Beheerder <emailAddress /> <cultureName>nl-NL</cultureName> </user> </LogOnResult> </LogOnResponse> </soap:Body></soap:Envelope>
parser code:
NSData *aData = [[NSData alloc] initWithBytes:[webData mutableBytes] length:[webData length]];
NSString *xmlData = [[NSString alloc] initWithData:aData encoding:NSASCIIStringEncoding];
NSLog(#"%#", xmlData);
[xmlData release];
CXMLDocument *domUserIdentity = [[[CXMLDocument alloc] initWithData:aData options:0 error:nil] autorelease];
[aData release];
NSArray *nodesList = [domUserIdentity nodesForXPath:#"//LogOnResult" error:nil]; // 0 length
for (CXMLElement *resultElement in nodesList) {
for (int counter = 0; counter
NSString *elemName = [[resultElement childAtIndex:counter] name];
NSString * elemValue = [[[resultElement childAtIndex:counter] stringValue] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
[elemName release];
[elemValue release];
}
}
[nodesList release];
Any idea what did i do wrong?
Thank's alot in advance.
Inoel

Try using the NSXMLDocument, it should work as well as CXMLDocument. Here are some docs:
link

I recommend using an XPath Parser. You aren't doing anything too heavy, so the speed hit is well worth it. My personal choice is TFHpple. There are slightly faster and more precise solutions out there, but I find TFHpple's simplicity hard to beat.
Example:
NSData *data = [[NSData alloc] initWithContentsOfFile:#"example.html"];
// Create parser
xpathParser = [[TFHpple alloc] initWithXMLData:data];
NSArray *elements = [xpathParser search:#"//LogOnResult"];
TFHppleElement *element = [elements objectAtIndex:0];
// Get the text within the cell tag
NSString *content = [element content];
[xpathParser release];
[data release];
Obviously you'd have to write some code to save the parts you want. Looking at this data, I'd probably make a custom data holder class that you can access with properties. You can parse your XML into that and then save it as a property in the view controller that will be accessing it.
Happy coding!

Related

XCODE NSXML changing the element value

I have a very simple xml file by name options.xml
<Dat>
<Name>Tom</Name>
<Option>1</Option>
</Dat>
Using NSXML I am trying to change "Tom" to "Jim" and save the file. How can I do that. I read many document and there is no straight forward solution. Can some one help me with the code ?
update: I ended up in trying with Gdatasxml
-(void)saveToXML
{
NSString* path = [[NSBundle mainBundle] pathForResource:#"options" ofType:#"xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:path];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
GDataXMLElement *rootElement = [GDataXMLElement elementWithName:#"Dat"];
NSArray *mySettings = [doc.rootElement elementsForName:#"Dat"];
for (GDataXMLElement *mySet in mySettings)
{
NSString *name;
NSArray *names = [mySet elementsForName:#"Name"];
if (names.count > 0)
{
GDataXMLElement *childElement = (GDataXMLElement *) [names objectAtIndex:0];
name = childElement.stringValue;
NSLog(childElement.stringValue);
[childElement setStringValue:#"Jim"];
}
}
[xmlData writeToFile:path atomically:YES];
}
But this is not saving the data. Help.
Editing XML is a little difficult in iOS. You need to parse the original xml to a model and then form the xml.
You can make use of 3rd party library such as GDataXML for forming XML from a data source.
//Edited user info saved in a dictionary
NSDictionary *dictionary = #{#"Name": #"Jim", #"Option":#"1"};
GDataXMLElement *rootElement = [GDataXMLElement elementWithName:#"Dat"];
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
GDataXMLElement *element = [GDataXMLElement elementWithName:key stringValue:obj];
[rootElement addChild:element];
}];
//xml document is formed
GDataXMLDocument *document = [[GDataXMLDocument alloc]
initWithRootElement:rootElement];
NSData *xmlData = document.XMLData;
NSString *filePath = [self savedXMLPath];
//XML Data is written back to a filePath
[xmlData writeToFile:filePath atomically:YES];
Create a class that is essentially an XML "node". Then in your parser setup a system of these XML nodes in the same fashion as you read them. Then search through that body and find the element that you would like to change. Change it. Then write a function that goes through these "node" objects and writes a new NSString in XML format and save that string to file. There is no real easy way that I know of to write XML files. I'm sure someone has a library out there to do it, but I had very complex XML's to deal with so I wrote my own. If you would like specific code let me know and I can try to give you parts of what you may need.
You Can use GDATAXML for changing XML node
Here is Working Code snippet
NSString *XMLString = #"<Dat><Name>Tom</Name><Option>1</Option></Dat>";
NSError *error = nil;
GDataXMLElement *newElement = [[GDataXMLElement alloc] initWithXMLString: XMLString error: &error];
NSLog(#"New element: %# error: %#", newElement, error);
if(nil == error)
{
GDataXMLElement *childElement = [[newElement elementsForName: #"Name"] objectAtIndex: 0];
[childElement setStringValue:#"Jim"];
childElement = [[newElement elementsForName: #"Option"] objectAtIndex: 0];
[childElement setStringValue:#"2"];
}
NSLog(#"New element now: %#", newElement);
Check by using this code snippet

Xml parser atttributes

I am working on XMLParser. I used NSLog and get a following xml string :
<table><tr><td><img src="http://www.24h.com.vn/upload/3-2012/images/2012-09-16/1347762760_bong-da-genoa-juve.jpg"width='80' height='80' /></td><td>(20h, 16/9) Juventus sẽ có trận đấu khó khăn tới sân của Genoa.</td></tr></table>
how to get link in img src.
I tried:
else if([elementName isEqualToString:#"img"])
{
currentString=[attributeDict objectForKey:#"src"];
self.storingCharacter=YES;
}
But unsuccessful. Any help?
You need to implement an html parser to get the objects you wanted. I suggest you to use hpple.
I took the snippet of Albaregar solution from parsing HTML on the iPhone and modified it to your needs. I didn't test the adapted snippet, but it should works.
#import "TFHpple.h"
NSData *data = [[NSData alloc] initWithContentsOfFile:#"yourfile.html"];
// Create parser
xpathParser = [[TFHpple alloc] initWithHTMLData:data];
//Get the first img tag
NSArray *elements = [xpathParser searchWithXPathQuery:#"//img[0]"];
// Access the first img attribute src
TFHppleElement *element = [elements objectAtIndex:0];
// Get the text within the src attribute
NSString *src_attr = [element content];
[xpathParser release];
[data release];

How to handle Spanish character in my App?

In my app i have a service which supports spanish and return the result in spanish.
Now i am trying to pass some search term to this service to get the result back but its failing because while sending compiler converts the word to some funny word with unidentified characters.
I am doing this:
name here is coming in spanish but when i am adding this in the config dictionary it gets converted again to some funny thing.
-(void)perfromLocationSearchWithName:(NSString *)name{
NSData * nameCode = [[NSData alloc]init];
nameCode = [name dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString * namePass = [[NSString alloc]initWithData:nameCode encoding:NSUTF8StringEncoding];
NSLog(#"Name:%#",namePass);
NSMutableDictionary *config = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease];
NSString * strAction = [NSString stringWithFormat:#"vendorSearchByName"];
if (namePass !=nil){
[config setObject:namePass forKey:#"vendorName"];
//[config setObject:#"001" forKey:#"MakeCode"];
[config setObject:#"5" forKey:#"maxCount"];
[config setObject:strAction forKey:#"action"];
}
NSLog(#"Dict%#",[config description]);
comm = [[CommManager alloc] init];
[comm searchDealerLocationWithOptions:config withDelegate:self];
[namePass release];
}
Please help
Thanks,
Try using NSISOLatin1StringEncoding. Helped us in our app.

Parsing JSON to get Google Reader Label information

I am trying to make a google reader app. I am able to get the subscription list in JSON format like this:
{"subscriptions":[{"id":"feed/http://aspn.activestate.com/ASPN/Cookbook/Python/index_rss","title":"ActiveState Code: Python recipes","categories":[{"id":"user/014533032765194560dwd0/label/Programming","label":"Programming"}],"sortid":"E6312EFB","firstitemmsec":"1258141669516","htmlUrl":"http://code.activestate.com/recipes/langs/python/"},
I am interested in getting the label value (in the above case "Programming") into an array. Here is my current code:
-(BOOL)parsedSuccess {
SBJsonParser *parser = [[SBJsonParser alloc]init];
if (!receivedData) {
[self getSubscriptionList:GOOGLE_READER_SUBSCRIPTION_LIST];
}
NSMutableString *body = [[NSMutableString alloc]initWithData:receivedData encoding:NSUTF8StringEncoding];
if (body) {
NSArray *feeds = [parser objectWithString:body error:nil];
NSDictionary *results = [body JSONValue];
NSArray *subs = [results valueForKey:#"subscriptions"];
NSString *subTitles;
for (NSDictionary *title in subs){
subTitles = [title objectForKey:#"categories"];
NSLog(#"%#",subTitles);
}
}
return YES;
}
Can someone help me in getting the label values?
[[[[[result valueforkey:#"subscription"]objectatindex:0]valueforkey:#"categories"]objectatindex:intvalue]valueforkey:#"label"];
I just helped to make logic. Be sure to check for spelling mistakes before implementing.

NSMutableString stringByReplacingOccurrencesOfString Warning

I've got an RSS parser method and I need to remove whitespace and other nonsense from my extracted html summary. I've got a NSMutableString type 'currentSummary'. When I call:
currentSummary = [currentSummary
stringByReplacingOccurrencesOfString:#"\n" withString:#""];
Xcode tells me "warning: assignment from distinct Objective-C type"
What's wrong with this?
If currentSummary is already a NSMutableString you shouldn't attempt to assign a regular NSString (the result of stringByReplacingOccurrencesOfString:withString:) to it.
Instead use the mutable equivalent replaceOccurrencesOfString:withString:options:range:, or add a call to mutableCopy before the assignment:
// Either
[currentSummary replaceOccurencesOfString:#"\n"
withString:#""
options:NULL
range:NSMakeRange(0, [receiver length])];
// Or
currentSummary = [[currentSummary stringByReplacingOccurrencesOfString:#"\n"
withString:#""]
mutableCopy];
This works great for nested elements as well of course:
*Edited*
// Get the JSON feed from site
myRawJson = [[NSString alloc] initWithContentsOfURL:[NSURL
URLWithString:#"http://yoursite.com/mobile_list.json"]
encoding:NSUTF8StringEncoding error:nil];
// Make the content something we can use in fast enumeration
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary * myParsedJson = [parser objectWithString:myRawJson error:NULL];
[myRawJson release];
allLetterContents = [myParsedJson objectForKey:#"nodes"];
// Create arrays just for the title and Nid items
self.contentTitleArray = [[NSMutableArray alloc]init];
for (NSMutableDictionary * key in myArr) {
NSDictionary *node = [key objectForKey:#"node"];
NSMutableString *savedContentTitle = [node objectForKey:#"title"];
// Add each Title and Nid to specific arrays
//[self.contentTitleArray addObject:contentTitle];
//change each item with & to &
[self.contentTitleArray addObject:[[savedContentTitle
stringByReplacingOccurrencesOfString:#"&"
withString:#"&"]
mutableCopy]];
}
The code below, as shown in the use-case above might be helpful.
[self.contentTitleArray addObject:[[contentTitle
stringByReplacingOccurrencesOfString:#"&"
withString:#"&"]
mutableCopy]];
That usually means you dropped the asterisks in the definition of (in this case) currentSummary.
So you most likely have:
NSMutableString currentSummary;
when you need:
NSMutableString *currentSummary;
In the first case, since Objective-C classes are defined in type structures, the complier thinks your trying to assign a NSString to a struct.
I make this typo on a distressingly regular basis.