Unable to parser using TouchXML - iphone

I am unable to parse response recieve using Touch XML My response from SOAP
<CXMLDocument 0x4b30110 [0x4b34c90]> <?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>
<GetImagesResponse xmlns="http://tempuri.org/">
<GetImagesResult>;http://www.google.com;http://www.hotmail.com;http://www.yahoo.com</GetImagesResult>
</GetImagesResponse>
</soap:Body>
</soap:Envelope>
/// Touch XML function
-(void) grabRSSFeed:(NSData *)responseData {
// Initialize the blogEntries MutableArray that we declared in the header
self.rssEntries = [[[NSMutableArray alloc] init] autorelease];
// Create a new rssParser object based on the TouchXML "CXMLDocument" class, this is the
// object that actually grabs and processes the RSS data
CXMLDocument *rssParser = [[CXMLDocument alloc] initWithData:responseData options:0 error:nil];
//CXMLDocument *rssParser = [[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil];
NSLog(#"rssParser %#",rssParser);
//NSLog(#"url %#",url);
// Create a new Array object to be used with the looping of the results from the rssParser
NSArray *resultNodes = NULL;
// Set the resultNodes Array to contain an object for every instance of an node in our RSS feed
resultNodes = [rssParser nodesForXPath:#"//GetImagesResult" error:nil];
// Loop through the resultNodes to access each items actual data
for (CXMLElement *resultElement in resultNodes) {
// Create a temporary MutableDictionary to store the items fields in, which will eventually end up in blogEntries
NSMutableDictionary *blogItem = [[[NSMutableDictionary alloc] init] autorelease];
// Create a counter variable as type "int"
int counter;
// Loop through the children of the current node
for(counter = 0; counter < [resultElement childCount]; counter++) {
//[resultElement initWithXMLString:#""];
NSString *strValue = [[resultElement childAtIndex:counter] stringValue];
//strValue = [strValue stringByReplacingOccurrencesOfString:#"\n" withString:#""];
NSString *strName = [[resultElement childAtIndex:counter] name];
if ([resultNodes containsObject:#""] || resultNodes == nil || resultElement == nil || [resultElement isEqual:#""] || [resultElement children] == nil) {
NSLog(#"Null Object");
}
else {
if (strValue && strName) {
// Add each field to the blogItem Dictionary with the node name as key and node value as the value
[blogItem setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
}
}
}
// Add the blogItem to the global blogEntries Array so that the view can access it.
[self.rssEntries addObject:[blogItem copy]];
NSLog(#"RSS Entries %#",self.rssEntries);
}
[[rssParser retain] release];
}

Being "unable to parse response" is a very vague description of your problem. However, at first glance I noticed that this XPath query...
resultNodes = [rssParser nodesForXPath:#"//GetImagesResult" error:nil];
...is most likely not matching any elements and thus returning an empty array.
Why? Your XML has a namespace. Use nodesForXPath:namespaceMappings:error: method instead of nodesForXPath:error:. The former has an extra parameter that lets you provide a namespace mapping dictionary. Then edit your XPath query accordingly. See the example below:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
#"http://tempuri.org/",
#"tempuri",
nil];
// Set the resultNodes Array to contain an object for every instance of an node in our RSS feed
resultNodes = [rssParser nodesForXPath:#"//tempuri:GetImagesResult" namespaceMappings:dict error:nil];
Also, the last statement of the method is nonsense:
[[rssParser retain] release];
To balance the alloc-init, it should be:
[rssParser release];

Related

iPhone - difference between GDataXMLNode and GDataXMLElement, and how to use them

As the google doc is not available anymore, I'm lost with those concepts.
What is a node, and what is an element (that inherits the node) ?
How can I switch from nodes to elements. I mean, for example, if I write :
NSError* error;
NSData* xmlData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"ForTesting" ofType:#"xml"]];
error = nil;
GDataXMLDocument* XMLDoc = [[[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error] autorelease];
if (XMLDoc == nil) {
NSLog(#"%#", error.description);
return;
}
GDataXMLNode* xmlElement = [[XMLDoc nodesForXPath:#"//root/fileVersion" error:nil] objectAtIndex:0];
NSString* fileVersion = xmlElement.stringValue;
GDataXMLNode* xmlList = [[XMLDoc nodesForXPath:#"//root/list" error:nil] objectAtIndex:0]; // single item
After that code, how can I write something like that to switch to GDataXMLElement instead of continuing with GDataXMLNode, that would requires me to continue using XPath (I don't want to use it past that point) :
// code don't work : elementsForName is not defined for GDataXMLNode
for (GDataXMLElement* xmlObject in [xmlList elementsForName:#"object"]) {
MyClass* obj = [[[MyClass alloc] initWithXMLElement:xmlObject] autorelease];
}
GDataXMLNode is obviously the classes you use for XML parser- GDataXMLNode.h/.m
In the code you have given returns an array. You can use.
NSArray *myArray = [XMLDoc nodesForXPath:#"//root/fileVersion" error:nil];
You can iterate myArray like this.
for (GDataXMLElement *nodeXmlElt in myArray)
{
//some code
}
Each of my nodeXmlElt will be like given below.
<fileVersion>
<title>San Francisco CBS News</title>
<link>http://news.google.com/news/</link>
<fileVersion>
//getting title
NSArray *elementArray = [nodeXmlElt elementsForName:#"title"];
GDataXMLElement *gdataElement = (GDataXMLElement *)[elementArray objectAtIndex:0];
NSString *title = gdataElement.stringValue; //returns 'San Francisco CBS News'

How can I parse this xml using GDataXML parser?

<list>
<OrderData HASH="1408108039"></OrderData>
<OrderData HASH="208524692">
<id>97</id>
<customer>
<CustomerData HASH="2128670187"></CustomerData></customer>
<billingAddress></billingAddress><deliveryAddress></deliveryAddress>
<orderDetail>
<list>
<OrderDetailData HASH="516790072"></OrderDetailData>
<OrderDetailData HASH="11226247"></OrderDetailData>
<OrderDetailData HASH="11226247"></OrderDetailData>
</list>
</orderDetail>
<log/>
</OrderData>
<OrderData HASH="1502226778"></OrderData>
</list>
I cannot find a solution to find the number of OrderDetailData elements? I also read http://iphonebyradix.blogspot.com/2011/03/using-gdata-to-parse-xml-file.html this url.
Thanks in advance.
Edit:
I am explaining my requirement again. In this xml there will be multiple OrderData element. Now I have to count the number of OrderDetailData elemnts from a particular OrderData element. Suppose that, according to my xml, the current parsed xml has one OrderData element, named id and its value is 97. Now, I have to count how many OrderDetailData elements are contained in the OrderData(whichid` is 97).
This is a simple example how to retrieve some data. This example is very simple and not use XPath expression. I suggest you first understand how it works and then use XPath expression. In my opinion it is not useful to use XPath expression if you cannot understand how the parser works.
NSString* path = [[NSBundle mainBundle] pathForResource:#"test2" ofType:#"xml"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:path];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData
options:0 error:&error];
//NSLog(#"%#", doc.rootElement); // print the whole xml
NSArray *orderDataArray = [doc.rootElement elementsForName:#"OrderData"];
for (GDataXMLElement *orderDataElement in orderDataArray) {
if([orderDataElement childCount] > 0)
{
NSString *attributeForOrderDataElement = [(GDataXMLElement *) [orderDataElement attributeForName:#"HASH"] stringValue];
NSLog(#"attributeForOrderDataElement has value %#", attributeForOrderDataElement);
GDataXMLElement* idElement = (GDataXMLElement*)[[orderDataElement elementsForName:#"id"] objectAtIndex:0];
NSLog(#"id has value %#", idElement.stringValue);
GDataXMLElement* orderDetailElement = (GDataXMLElement*)[[orderDataElement elementsForName:#"orderDetail"] objectAtIndex:0];
GDataXMLElement* listElement = (GDataXMLElement*)[[orderDetailElement elementsForName:#"list"] objectAtIndex:0];
NSArray* orderDetailDataArray = [listElement elementsForName:#"OrderDetailData"];
int count = 0;
for (GDataXMLElement *orderDetailDataElement in orderDetailDataArray) {
NSString *attributeForOrderDetailDataElement = [(GDataXMLElement *) [orderDetailDataElement attributeForName:#"HASH"] stringValue];
NSLog(#"attributeForOrderDetailDataElement has value %#", attributeForOrderDetailDataElement);
count++;
}
NSLog(#"%d", count);
}
}
[doc release];
[xmlData release];
This is the output console:
attributeForOrderDataElement has value 208524692 <-- HASH value
id has value 97 <-- id value
attributeForOrderDetailDataElement has value 516790072 <-- HASH value
attributeForOrderDetailDataElement has value 11226247
attributeForOrderDetailDataElement has value 11226247
3 <-- the count
Hope it helps.
Edit
test2.xml contains your file but you could pass it as a string. You can also pass as parameters as string like the following:
NSString* xmlString = #"<list>"
"<OrderData HASH=\"1408108039\"></OrderData>"
"<OrderData HASH=\"208524692\">"
"<id>97</id>"
"<customer>"
"<CustomerData HASH=\"2128670187\"></CustomerData>"
"</customer>"
"<billingAddress></billingAddress>"
"<deliveryAddress></deliveryAddress>"
"<orderDetail>"
"<list>"
"<OrderDetailData HASH=\"516790072\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"</list>"
"</orderDetail>"
"<log/>"
"</OrderData>"
"<OrderData HASH=\"1502226778\"></OrderData>"
"</list>";
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithXMLString:xmlString options:0 error:&error];
I found TouchXML easy in parsing and you can directly access data needed from xml
First of all Download TouchXML and add libxml2.dylib framework to your project.
change buildsetting for "Header Search Path" and add "/usr/include/libxml2"
Import TouchXML.h to your file
//Access document
CXMLDocument *parserDoc = [[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:&err];
//Access root element and access children in heirarchy
CXMLElement *root = [parserDoc rootElement];
NSArray *places = [[[root children] objectAtIndex:0] children];
Else
//Access node by node
NSString *location =[[[[[parserDoc nodesForXPath:#"/xml_api_reply/weather/forecast_information/city" error:nil] objectAtIndex:0] attributeForName:#"data"] stringValue] retain];
If the OrderDetailData is present in 2nd object of array all the time, u can use the below
NSArray* arr = [[XMLelement elementForName:#"list"] elementsForName:#"OrderData"];
NSXMLElement* listElement = [[[arr objectAtIndex:1] elementForName:#"orderDetail"] elementForName:#"list"];
NSArray* orderDetailArray* = [listElement elementsForName:#"OrderDetailData"];
In this u can get the OrderDetailData elements in the array, and u can parse the data in loop. to get HASH value use.
NSString* hash = [[orderDetailArray objectAtIndex:0] stringValueForAttribute:#"HASH"];
This is the below code, i have tried. I got the right output.. check out
NSString* xmlString = #"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<list>"
"<OrderData HASH=\"1408108039\"></OrderData>"
"<OrderData HASH=\"208524692\">"
"<id>97</id>"
"<customer>"
"<CustomerData HASH=\"2128670187\"></CustomerData></customer>"
"<billingAddress></billingAddress><deliveryAddress></deliveryAddress>"
"<orderDetail>"
"<list>"
"<OrderDetailData HASH=\"516790072\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"<OrderDetailData HASH=\"11226247\"></OrderDetailData>"
"</list>"
"</orderDetail>"
"<log/></OrderData>"
"<OrderData HASH=\"1502226778\"></OrderData>"
"</list>";
NSXMLDocument* doc = [[NSXMLDocument alloc] initWithData:[xmlString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSXMLElement* rootElement = [doc rootElement];
NSArray* arr = [rootElement elementsForName:#"OrderData"];
NSXMLElement* orderDataElement;
for (int i = 0; i < [arr count]; i++)
{
int Id = 0;
Id = [[arr objectAtIndex:i] integerValueForNode:#"id"];
if (Id != 0)
{
orderDataElement = [arr objectAtIndex:i];
break;
}
}
NSArray* orderDetailArray = [[[orderDataElement elementForName:#"orderDetail"]
elementForName:#"list"]
elementsForName:#"OrderDetailData"];
for (int j = 0; j < [orderDetailArray count]; j++)
{
NSLog(#"%#", [[orderDetailArray objectAtIndex:j] stringValueForAttribute:#"HASH"]);
}

How can i Parse xml data using GDataXML parser in iPhone application development?

-<stat>
<visitor>4</visitor>
<uniqueVisitor>2</uniqueVisitor>
<order>41</order>
<revenue>20658</revenue>
<conversionRate>48</conversionRate>
<newProduct>25</newProduct>
<outOfStockProduct>11</outOfStockProduct>
</stat>
From this xml i want to get the element name "visitor" & "uniqueVisitor" and their corresponding values using GDataXML parser.
Till now i have done these.
xmlFileLocation = [NSURL URLWithString:#"someurl....abc.php"];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfURL:xmlFileLocation];
xmlDocument = [[GDataXMLDocument alloc]initWithData:xmlData options:0 error:&error];
if (nil == xmlDocument) {
NSLog(#"could not load Branch.xml file");
}
else {
NSLog(#"Loading desire xml url for dashboard");
[self GDataXmlParser];
}
Using a tutorial i have done this till now. But now i want all of these element name and their corresponding values
-(void)GDataXmlParser{
NSArray *getData = [[xmlDocument rootElement]elementsForName:#"stat"];
records = [[NSMutableArray alloc]init];
tempArray = [[NSMutableArray alloc]init];
for(GDataXMLElement *e in getData){
// What i have to do here????
}
}
look at the answer
NSLog(#"%#", xmlDocument.rootElement);
records = [[NSMutableArray alloc] init];
NSLog(#"Enering in the xml file");
NSString *Visitor = [[[xmlDocument.rootElement elementsForName:#"visitor"] objectAtIndex:0] stringValue];
NSLog(#"Visitor : %#",Visitor);
NSString *UVisitor = [[[xmlDocument.rootElement elementsForName:#"uniqueVisitor"] objectAtIndex:0] stringValue];
NSLog(#"Unique Visitor : %#",UVisitor);
for more see the link I am not able to parse xml data using GDataXML
Follow this link for tutorial :http://iphonebyradix.blogspot.com/2011/03/using-gdata-to-parse-xml-file.html
-(void) GDataXmlParser
{
xmlDocument = [[GDataXMLDocument alloc]initWithData:xmlData
options:0
error:nil];
NSArray *temp = [xmlDocument.rootElement elementsForName:#"stat"];
NSMutableArray *records = [[NSMutableArray alloc]init];
for(GDataXMLElement *e in temp)
{
[records addObject:e];
NSString *Visitor = [[[e elementsForName:#"visitor"] objectAtIndex:0] stringValue];
NSLog(#"Visitor : %#",Visitor);
NSString *UVisitor = [[[e elementsForName:#"uniqueVisitor"] objectAtIndex:0] stringValue];
NSLog(#"Unique Visitor : %#",UVisitor);
}
}
Hope it helps you. Happy iCoding.

how to call a function within class in objective c

i am new to objective c programming I want to call a function within anothor method please give me idea.
-(void) grabRSSFeed:(NSString *)blogAddress {
// Initialize the blogEntries MutableArray that we declared in the header
myBlogEntries = [[NSMutableArray alloc] init];
// Convert the supplied URL string into a usable URL object
NSURL *url = [NSURL URLWithString: blogAddress];
// Create a new rssParser object based on the TouchXML "CXMLDocument" class, this is the
// object that actually grabs and processes the RSS data
CXMLDocument *rssParser = [[[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil] autorelease];
// Create a new Array object to be used with the looping of the results from the rssParser
NSArray *resultNodes = NULL;
// Set the resultNodes Array to contain an object for every instance of an node in our RSS feed
resultNodes = [rssParser nodesForXPath:#"//item" error:nil];
// Loop through the resultNodes to access each items actual data
for (CXMLElement *resultElement in resultNodes) {
// Create a temporary MutableDictionary to store the items fields in, which will eventually end up in blogEntries
NSMutableDictionary *blogItem = [[NSMutableDictionary alloc] init];
// Create a counter variable as type "int"
int counter;
// Loop through the children of the current node
for(counter = 0; counter < [resultElement childCount]; counter++) {
// Add each field to the blogItem Dictionary with the node name as key and node value as the value
[blogItem setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
}
// Add the blogItem to the global blogEntries Array so that the view can access it.
[myBlogEntries addObject:[blogItem copy]];
}
}
want to call above function in Babes Method
-(IBAction)babes
{
myview.hidden = FALSE;
[myview startAnimating];
feedurl = #"http://www.luxury.net/feed/rss/babes.xml";
//want to call it here.....
[self performSelector:#selector(moveAlert:) withObject:nil afterDelay: 0.7f];
}
but its not working please help me out thanks in advance.
You need to read the beginner documentation, start here: Learning Obj-C
For your problem specifically, try this:
NSString* aBlogAdress = #"http://anAdress.com";
[self grabRSSFeed:aBlogAddress];
You use self just as you are doing already, but you have to supply the argument correctly.
[self grabRSSFeed:#"http://someurl.com"];
The blogAddress is an NSString that you must supply somehow. For example, if you have a text view called textViewRSSFeed in your app, you would supply the value for that field.
[self grabRSSFeed:textViewRSSFeed.text];
-(void)grabRssFeed:(NSString *)str
{
}
-(void)ViewDidLoad
{
NSString *Str=#"www.anyUrl.com";
[Self grabRssFeed:Str];
}

Parsing multiple and multi-level nested elements with TouchXML

I have an XML with the following structure and I am trying to create my model object from this. Can someone please help me find a way to get these objects from the XML using TouchXML, NSMutableArray and NSMutableDictionay.
<?xml version="1.0" encoding="utf-8"?>
<response>
<level1_items>
<level1_item>
<item_1>text</item_1>
<item_2>text</item_2>
</level1_item>
<level1_item>
<item_1>some text</item_1>
<item_2>some more text</item_2>
</level1_items>
<items>
<item>
<child_items>
<child_item>
<leaf1>node text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>some text</leaf3>
</child_item>
<child_item>
<leaf1>text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>more text</leaf3>
</child_item>
</child_items>
</item>
<item>
<child_items>
<child_item>
<leaf1>node text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>some text</leaf3>
</child_item>
<child_item>
<leaf1>text</leaf1>
<leaf2>leaf text</leaf2>
<leaf3>more text</leaf3>
</child_item>
</child_items>
</item>
</items>
</response>
I need to parse the <response> and its children.
First off, I have to say that your XML will be difficult to work with because you are trying to use a specific tag for each item in a list. For example:
<level1_items>
<level1_item>
<item_1>text</item_1>
<item_2>text</item_2>
</level1_item>
<level1_item>
<item_1>some text</item_1>
<item_2>some more text</item_2>
</level1_items>
the tags named <item_ 1>, <item_ 2> don't make sense as XML is intended to describe your data, not define it. If you have an entity called an item, you should probably just call it item and make the XML look like this:
<level1_items>
<level1_item>
<item index="1">text</item>
<item index="2">text</item>
</level1_item>
<level1_item>
<item index="1">some text</item>
<item index="2">some more text</item>
</level1_items>
Where each item has an index. For that matter, you could just load the document in your TouchXML CXMLDocument and grab the nodes you need with XPath and assume they're in the correct order ignoring the index= parameter I specified.
The next issue is that converting XML to an NSDictioanry or NSArray of dictionaries is a pretty involved task and what you gain isn't worth the effort. Just load your XML into a CXMLDocument and then start obtaining nodes using XPath. Something like this:
CXMLDocument *doc = [[CXMLDocument alloc] initWithXMLString:xmlString options:0 error:nil];
// Returns all 'level1_item' nodes in an array
NSArray *nodes = [[doc rootElement] nodesForXPath:#"//response/level1_items/level1_item" error:nil];
for (CXMLNode *itemNode in nodes)
{
for (CXMLNode *childNode in [itemNode children])
{
NSString *nodeName = [childNode name]; // should contain item_1 in first iteration
NSString *nodeValue = [childNode stringValue]; // should contain 'text' in first iteration
// Do something with the node data.
}
}
I suggest trying to use the XML this way and then come back here and ask specific questions if you have problems.
-(NSMutableArray *)parseNodeFromXML:(NSString *)strXML readForNode:(NSString *)strReadValue
{
NSError *theError = NULL;
CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:strXML options:0 error:&theError] ;
NSMutableArray *arrReturn = [[NSMutableArray alloc] init];
NSArray *nodes = [[theXMLDocument rootElement] nodesForXPath:strReadValue error:nil];
for (CXMLNode *itemNode in nodes)
{
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
// PROCESS FOR READ ELEMENT ATTRIBUTES IN CURRENT NODE -------------------------
if([itemNode isMemberOfClass:[CXMLElement class]]){
CXMLElement *elements=(CXMLElement*)itemNode;
NSArray *arAttr=[elements attributes];
for (int i=0; i<[arAttr count]; i++) {
if([[arAttr objectAtIndex:i] name] && [[arAttr objectAtIndex:i] stringValue]){
[dic setValue:[[arAttr objectAtIndex:i] stringValue] forKey:[[arAttr objectAtIndex:i] name]];
}
}
}
// PROCESS FOR READ CHILD NODE IN CURRENT NODE -------------------------
for (CXMLNode *childNode in [itemNode children])
{
// NSLog(#"count -- %d --- %#",[childNode childCount],[childNode children]);
// IF ANY CHILD NODE HAVE MULTIPLE CHILDRENS THEN DO THIS....-
if ([childNode childCount] > 1)
{
NSMutableDictionary *dicChild = [[NSMutableDictionary alloc] init];
for (CXMLNode *ChildItemNode in [childNode children])
{
[dicChild setValue:[ChildItemNode stringValue] forKey:[ChildItemNode name]];
}
[dic setValue:dicChild forKey:[childNode name]];
}else
{
[dic setValue:[childNode stringValue] forKey:[childNode name]];
}
}
[arrReturn addObject:dic];
}
// NSLog(#"%#",arrReturn);
return arrReturn;
}
may this help for multiple get child