How to parse complex XML tree using TouchXml in iPhone - iphone

I am trying to build an app which during start-up connects to website and downloads the XML data. Though the data is large(100 KB) and i am using TouchXml for it. The xml is like this.
<?xml version="1.0" encoding="UTF-8"?>
<itemA attA="AAA" attB="BBB" attC="CCC">
<itemB>
<itemC1 attD="DDD" attE="EEE" attF="FFF">
<itemD>
<itemE1 attG="GGG">
<itemF>ZZZ</itemF>
<itemG>
<itemH1 attH="HHH">
<itemG>ZZZ</itemG>
<itemH>YYY</itemH>
</itemH1>
<itemH1 attH="III">
...
</itemG>
</itemE1>
...
</itemD>
</itemC1>
...
</itemB>
</itemA>
Here three dots ". . ." presents tens/hundreds of same kind of element. i want to extract each and every attribute and node contents. Initailly i begin with
[CXMLDocument nodesForXPath:#"//itemA" error:nil];
and able to get its attributes and upto first child nodes using -
[CXMLElement childAtIndex:index];
but how i will move further into child nodes and their nodes and get their values. Any help is greatly appreciated.link text

You can use XPaths for this:-
NSArray *nodes = [doc nodesForXPath:#"//itemA/itemB/itemC1" error:nil];
This will return all the nodes in the itemC1 element. Note 'doc' is your CXMLDocument object.
Google XPath for the full syntax.

You would probably definitely be better served with using the event-driven parser in this case; NSXMLParser.

Related

XML generation and parsing from Core data in iphone

I'm creating a simple iOS application consisting of a few UITableViewControllers. The information displayed in the view controllers will come from a xml file (that I'll include in the project's Resources or direct from dropbox or iCloud). The xml file's contents will be based on user input .
A few notes:
The data is based on the user input means not static. Ideally the app will load the data into "Core Data" from xml file.
Each additional run of the app will just pull data from some Core Data source (that I'm not completely familiar w/ yet) instead of re-loading it from the textfile.
right now I am using XMLwriter to generate simple xml file
Please guide me
thank you
The best pattern here seems to be to use the XML file to "seed" your Core Data database. This only happens the first time. After that you will never again use your XML file but simply update and sync your core data store.
This is far better than generating XML. The problem with XML files (like property lists) is that you have to write the entire file for each little incremental change. If you sync to a store somewhere online, this can take much too much time to be practical.
Assuming you can get a foundation object from the XML file, simply iterate through the object and insert a Core Data one by one.
for (NSDictionary *dict in xmlArray) {
Entity *newObject = [NSEntityDescription
insertNewObjectForEntityForName:#"Entity"
inManagedObjectContext:self.managedObjectContext];
newObject.attribute1 = [dict objectForKey:#"attribute1"];
newObject.attribute2 = [dict objectForKey:#"attribute2"];
// etc...
}
[self.managedObjectContext save:nil];

Loading text from a file

I am making an Iphone drinking card game app.
All the card mean something different and i want the user to be able to press an info button and then show a new screen with information about the current card. How can i make a document to load text from instead of using a bunch og long strings?
Thanks
You could look into plist files - they can be loaded quite easily into the various collection objects and edited with the plist editor in Xcode.
For instance, if you organize your data as a dictionary, the convenience constructor
+ (id)dictionaryWithContentsOfURL:(NSURL *)aURL
from NSDictionary would provide you with as many easily accessible strings as you need.
This method is useful if you consider your strings primarily data as opposed to UI elements.
Update:
As #Alex Nichol suggested, here is how you can do it in practice:
To create a plist file:
In your Xcode project, for instance in the Supporting Files group, select New File > Resource > Property List
You can save the file in en.lproj, to aid in localization
In the Property list editing pane, select Add Row (or just hit return)
Enter a key name (for instance user1) and a value (for instance "Joe")
To read the contents:
NSURL *plistURL = [[NSBundle mainBundle] URLForResource:#"Property List" withExtension:#"plist"];
NSLog(#"URL: %#", plistURL);
NSDictionary *strings = [NSDictionary dictionaryWithContentsOfURL:plistURL];
NSString *user1 = [strings objectForKey:#"user1"];
NSLog(#"User 1: %#", user1);
A plist, a JSON string, and an SQLite database walked into a bar ...
Oops!! I mean those are the three most obvious alternatives. The JSON string is probably the easiest to create and "transport", though it's most practical to load the entire thing into an NSDictionary and/or NSArray, vs read from the file as each string is accessed.
The SQLite DB is the most general, and most speed/storage efficient for a very large number (thousands) of strings, but it takes some effort to set it up.
In my other answer, I suggest the use of a dictionary if your texts are mostly to be considered as data. However, if your strings are UI elements (alert texts, window titles, etc.) you might want to look into strings files and NSBundle's support for them.
Strings files are ideally suited for localization, the format is explained here.
To read them into you app, use something like this:
NSString *text1 = NSLocalizedStringFromTable(#"TEXT1", #"myStringsFile", #"Comment");
If you call your file Localizable.strings, you can even use a simpler form:
NSString *str1 = NSLocalizedString(#"String1", #"Comment on String1");
A useful discussion here - a bit old, but still useful.

Sudzc with iOS 5 and ARC

I've been trying to get a webservices working using Sudzc. Whenever I convert my WSDL to obj-c without automatic reference counting it works just fine. The problem is, we are building all our applications in iOS 5 now and all our code uses ARC. Sudzc now also allows you to create a bundle with ARC enabled but when I run this code it always returns null.
I tried debugging the Sudzc code and it does receive a correct xml response back from the service. Somewhere something is lost in translation. I tried converting the working Sudzc code without ARC into code with ARC enabled but as soon as I've fixed all errors it returns null again.
Did anyone encounter this and know what is going wrong? Would save me loads of time not having to debug the whole Sudzc code by myself.
In my case (SUDZC with ARC for IOS), I have replaced the folowing code in SoapRequest.m file;
CXMLNode* element = [[Soap getNode: [doc rootElement] withName:#"Body"] childAtIndex:0];
with
CXMLNode* element = [[Soap getNode: [doc rootElement] withName:#"soap:Body"] childAtIndex:0];
Somehow the respective function is searching for the root element with name "Body". After inspecting the soap envelope it is easy to see the root element's name is "soap:Body".
My webService was create in Java with Axis Eclipse.
FOR ARC I use : "soapenv:Body"
And in the file SoapObject.m I add
#import "Soap.h"
#import "SoapObject.h"
In my case "env:Body" worked. Check your return xml (by printing) and replace appropriately
In my case it was an .Net web service (WCF) and I had to use s:Body:
Found out by printing the CXML document:
CXMLNode* test = [doc rootElement];
NSLog(#"%#",test);
Here I got this:
<CXMLElement 0x68c1a50 [0x68c1b10] s:Envelope <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><**s:Body**><GetUserIDResponse xmlns="http://tempuri.org/"><GetUserIDResult>8</GetUserIDResult></GetUserIDResponse></s:Body></s:Envelope>>
Thanks to previous posts I was able to find it out and posted the complete answer again on my blog: http://www.dailycode.info/Blog/post/2012/08/07/SUDZC-webservices-always-return-0-(WCF-web-service-and-IOS-client).aspx

Having trouble understanding how to work TBXML

I followed the TBXML guide and it's been successfully installed into my code, but the guide they have doesn't make sense to me. I want to get some values from an XML document. An example they have of starting this process is:
TBXML * tbxml = [[TBXML tbxmlWithURL:[NSURL URLWithString:#"http://www.w3schools.com/XML/note.xml"]] retain];
In NSLog, for me this returns:
<TBXML: 0x4e3cc90>
This example XML file contains the following:
<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>
Could somebody give me a quick example on how from this XML file i would be able to extract the <body> of this? Their guide does seem fairly straight forward looking at it, but I just can't seem to make sense of it.
http://www.tbxml.co.uk/TBXML/Guides_-_Loading_an_XML_document.html is their guide.
Andrew,
It appears that once you init TBXML with the xml file, as it appears you have, you then 'traverse' elements in the document using various API. I haven't tested this but it would appear in your example that "body" is a child of "note", therefore... first get the note element and from the root element and extract the body element from the note element.
TBXMLElement *noteElement = [TBXML childElementNamed:#"note" parentElement:rootXMLElement];
TBXMLElement *bodyElement = [TBXML childElementNamed:#"body" parentElement:noteElement];
You should be able to traverse on anything at this point.
-- Frank

get element value

I have a NSString like that? (in iPhone application)
NSString *xmlStr = "<?xml version=1.0 encoding=UTF-8>
<information>
<name>John</name>
<id>435346534</id>
<phone>045635456</phone>
<address>New York</address>
</information>"
How I can get elements value?
(Do i need convert to XML format and get elements value? or split string? any way please tell me?)
Thank you guys.
If you want to use split string, you can use tokenization of strings using "componentsSeparatedByString" method. This is a more cumbersome method of course, rather than the recommended XMLParser
To get the name.
NSArray *xmlStr_first_array = [xmlStr componentsSeparatedByString: #"<name>"];
NSString *xmlStr_split = [NSString stringWithFormat:#"%#",[xmlStr_first_array objectAtIndex:1]];
NSArray *xmlStr_second_array = [xmlStr_split componentsSeparatedByString: #"</name>"];
NSString *name = [NSString stringWithFormat:#"%#",[xmlStr_second_array objectAtIndex:0]];
The most obvious solution is to use an XML parser to retrieve the values from each element.
You could use the excellent TBXML for this task. It provides a really simple interface where it wouldn't take more than a few lines to retrieve the desired values. The drawback to using this small library is that it (as far as I know) loads the entire XML data into memory. In this particular case, however, that is not problem at all.
There's of course also the option of using the NSXMLParser, though this is an event-driven parser, and thus a bit less simple to use.
Your string is in xml format already and you need to parse it to retrieve data. There're several options available - for example you can use NSXMLParser class or libxml library.
Edit: XMLPerformance sample project shows how to use both approaches and compare their performance.