Parsing XML file with same name attributes in iphone using NSXMLParser? - iphone

I am creating an iPhone App in which I have to consume values from a service url.The response from url is of XML format.XML file has same name attributes many times,and those attributes are not static.I mean the no of attributes may increase from time to time. So I couldn't understand how to consume that XML response in iPhone.
My XML response looks like this :
GetUserResponse xmlns="http://schemas.datacontract.org/2004/07"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<CompanyList>
<User>
<Address>
<City>Alabaster</City>
<State>Alabama</State>
</Address>
<Employee>
<Name>DrJohn</Name>
</Employee>
</User>
<User>
<Address>
<City>SanFransisco</City>>
<State>California</State>
</Address>
<Employee>
<Name>DrWilliams</Name>
</Employee>
</User>
</CompanyList>
</GetUserResponse>
The thing is I couldn't say there will be specific number of tags as of 2 tags here.They may or may not increase from time to time.I think we should take something like count number of items and extract the values but couldn't understand how?

This is one of many ways to do it. You can simply get the attributeDict and parse all the values from it using key-value.
NSString *element;
- (void) viewDidLoad {
[super viewDidLoad];
cityArr = [[NSMutableArray alloc] init];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
element = elementName;
if ([elementName isEqualToString:#“Address”]) {
// initialize stings to store values of child elements
cityStr = [NSMutableString alloc] init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([element isEqualToString:#“City”])
cityStr appendString:string];// Append Values
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#“Address”]) {
[cityArr addObject:cityStr]; // Add strings to array/dictionary and release string
}
}

Related

Parse an XML file with same tags

I am having an XML file which needs to be parsed.
I have parse an XML before but it was simpler. Because this file has similar tags, I am not able to figure out how to parse it.
The xml file looks like this:
<resource classname="Quote">
<field name="name">USD/KRW</field>
<field name="price">1104.319946</field>
<field name="symbol">KRW=X</field>
<field name="ts">1350544190</field>
<field name="type">currency</field>
<field name="utctime">2012-10-18T07:09:50+0000</field>
<field name="volume">-56144</field>
</resource>
I want to get the price field and add it to an array. I tried the code below from some online examples but it's showing all field's values and I want only the price field.
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([[attributeDict objectForKey:#"name"] isEqualToString:#"price"])
{
currencyValuesString = [[NSMutableString alloc]init];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"field"])
{
[currencyValuesArray addObject:currencyValuesString];
}
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currencyValuesString = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
There is multiple problems with your code:
You alloc/init currencyValuesString when you enter your <field name="price"> tag, but you never release it (which will leak if you are not using ARC), and more importantly you don't use this allocated instance, because in your -parser:foundCharacters: you replace the value of this variable with a different string.
Thus the previously allocated NSMutableString is totally useless. And moreover, in case your fields would contain multiple chucks of text instead of one (<field name="price">1.234<b>€</b></field> for example), -parser:foundCharacters: would be called multiple times, but your code will always throw away the previous value and keep only the last chunk instead of adding them to the NSMutableString.
If fact, with your code there is no point having an NSMutableString as you don't use it as a mutable string but simply replace each value with a new one each time instead of appending it.
But also, each time you encounter a closing </field> tag, whatever this tag is, you perform [currencyValuesArray addObject:currencyValuesString]; but don't release the currencyValuesString (which is fine only if you use ARC, but will leak if you use Manual Reference Counting) and more importantly you will add this string to the array each time you encounter the closing </field> tag, whatever the name of the opening tag was. So you will add the price to your array as many times as you have </field> closing tags after your price.
So the right approach would be to:
Append the foundCharacters to your NSMutableString instead of replacing it
When you encounter the closing tag, add the price to the array but then release and set the price string back to nil immediately. This way the currencyValuesString will only be around between the <field name="price"> opening tag and its corresponding </field> closing tag, and not when parsing the other <field> tags
Only add the price to your array in the closing tag if the currencyValuesString is not nil
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([[attributeDict objectForKey:#"name"] isEqualToString:#"price"])
{
currencyValuesString = [[NSMutableString alloc]init];
}
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[currencyValuesString appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"field"] && (currencyValuesString != nil))
{
[currencyValuesArray addObject:currencyValuesString];
[currencyValuesString release]; // Only needed if not using ARC. Remove this line if you use ARC
currencyValuesString = nil; // so that the next closing tag won't readd the price
}
}
try this :
in .h
NSXMLParser *rssParser;
NSDictionary *myAttrDict;
NSString *currentElement;
NSMutableArray *prizeArr;
in .m:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"field"])
{
if([[attributeDict objectForKey:#"name"] isEqualToString:#"price"])
{
currentElement = #"price";
}
else{
currentElement = nil;
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if([currentElement isEqualToString:#"price"])
{
[prizeArr addObject:string];
}
NSLog(#"prizeArr :%#",prizeArr);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
}

Unable to Parse following XML?

I have continuous tags of img id="#", where # varies from 1 to 9.
The description of tags consists of floating values.
When I use the standard NSXML Parser, i not getting all the values.
My XML for reference:
<img id="1">-0.0111328,-0.0635608,0.152549,0.11211,-0.0250431,
-0.0370875,0.0862391,0.0970791,-0.0195908,
-0.00892297,0.0791795,0.0554013,0.00362028,0.0138572,0.0432729,
0.0253036,-0.0770325,0.14065,0.118424,0.1787,
0.0734354,0.160883,0.101831,0.237038,0.0681151,0.178331,
0.106532,0.224731,0.133766,0.222096,0.165214,0.240752,
-0.0280366,0.106239,0.052094,0.110642,
</img>
How would I parse the above XML?
Kindly, help me out.
Thanx
This is because parser:foundCharacters: does not deliver all characters at once. You need to concatenate all strings that you get between the callbacks of the parser:didStartElement:namespaceURI:qualifiedName:attributes: and parser:didEndElement:namespaceURI:qualifiedName: that you get for the <img> tag.
In the code below, buf is an NSMutableString ivar of your parser delegate.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
if ([qualifiedName isEqualToString:#"img"]) {
buf = [NSMutableString string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([qualifiedName isEqualToString:#"img"]) {
buf = [buf stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"Got %#", buf);
}
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[buf appendString:string];
}
Finally got it... i placed start and end tags for img id = '#'. My structure now looks like this:
<images>
<img id = '1'> -0.0111328,-0.0635608,0.152549,0.11211,-0.0250431,
-0.0370875,0.0862391,0.0970791,-0.0195908,
-0.00892297,0.0791795,0.0554013,0.00362028,0.0138572,0.0432729,
0.0253036,-0.0770325,0.14065,0.118424,0.1787,
0.0734354,0.160883,0.101831,0.237038,0.0681151,0.178331,
0.106532,0.224731,0.133766,0.222096,0.165214,0.240752,
-0.0280366,0.106239,0.052094,0.110642, ....
</img>
<img id = '2'> ...
</img>
....
....
</images>
<mapping>
<map>
<imgid> 1 </imgid>
<keyword> heavy </keyword>
</map>
<map>
<imgid> 2 </imgid>
<keyword> metal </keyword>
</map>
...
...
</mapping>
Placing start and end tags allowed me to parse the whole xml.
Earlier, the start and end tags were for individual images which only resulted in parsing of one img.
This made me add another key point while parsing XML.
Hope this helps others as well.

How to get a part of tag in XML (iOS)

How can I get some data from the tag of a xml file?
I have a tag like this:
`<link href="http://127.0.0.1:8580/directory/playlists/" rel="alternate" type="application/atom+xml;type=feed" />`
I would like to save the http link: http://127.0.0.1:8580/directory/playlists/
Can I use the NSXMLParser?
Thanks a lot!
You need to implement a delegate for the NSXMLParser that conforms to the NSXMLParserDelegate protocol. In this implementation implement at least this method:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"link"]) {
NSString* href = [attributeDict objectForKey:#"href"];
// Do you stuff with the href
}
}
The value you are after "http://127.0.0.1:8580/directory/playlists/" is called an attribute. It is the attribute of the element "link".
Check out the Apple documentation relating to XML processing and elements and attributes. For example, http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/XMLParsing/Articles/HandlingElements.html

Parsing XML file with NSXMLParser - getting values

I've got a XML file which contains some data I would like to use:
<?xml version="1.0" encoding="UTF-8" ?>
<items>
<item name="product" price="19.95" where="store">
This is the first product.
</item>
<item name="product2" price="39.95" where="online">
This is the second product.
</item>
<item name="product3" price="99.95" where="garagesale">
This is the third product.
</item>
</items>
If I made 4 arrays, one for the name, one for the price, one for where it was bought and one for its description, how would I get the data into the arrays?
I figured using NSXMLParser, but couldn't get name, price, where or the description.
I'm stuck on how to do this.
Any help appreciated.
First you need to create an object that does the parsing. It will instatiate the NSXMLParser instance, set itself as the delegate for the parser and then call the parse message. It can also be responsible for storing your four result arrays:
NSXMLParser * parser = [[NSXMLParser alloc] initWithData:_data];
[parser setDelegate:self];
BOOL result = [parser parse];
The message you are most interested in implementing in your delegate objects is didStartElement. This guy gets called for each element in your XML file. In this callback you can add your name, price & where attributes to their respective arrays.
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
// just do this for item elements
if(![elementName isEqual:#"item"])
return;
// then you just need to grab each of your attributes
NSString * name = [attributeDict objectForKey:#"name"];
// ... get the other attributes
// when we have our various attributes, you can add them to your arrays
[m_NameArray addObject:name];
// ... same for the other arrays
}
To get the value between the tags (e.g. "This is the first product.") you can override - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
in the follwing method
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"item"]) {
NSString *name=[attributeDict objectForKey:#"name"];
NSString *price=[attributeDict objectForKey:#"price"];
NSString *where=[attributeDict objectForKey:#"where"];
}
}
you have to consider the dictionary of item tag as an array and three tag (name,price and where)as the object at index 0,1,2

xml parsing iphone issue

I'm using the NSXMLParser however i dont quite understand how to display items from a xml correctly. E.g. i have this in the xml parser:
- (void) parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"level4"]) {
//add a book object to the array at the index determined by bookCount
self.bookCount++;
[books addObject:[[book alloc]init]];
//[books insertObject:[[book alloc]init] atIndex:self.bookCount];
}
if ([elementName isEqualToString:#"module"]) {
isFirstName = YES;
}
if ([elementName isEqualToString:#"moduleTitle"]) {
isLastName = YES;
}
if ([elementName isEqualToString:#"semester"]) {
isTitle = YES;
}
if ([elementName isEqualToString:#"assessmentName"]) {
isGenre = YES;
}
}
This is my xml
<myCourse>
<courseName>BEng Mobile and Web Computing</courseName>
<courseStructure>
<level4>
<module>
<moduleCode>ECSC401</moduleCode>
<moduleTitle>Programming Methodology</moduleTitle>
<credits>15</credits>
<semester>1</semester>
<assessmentDetails>
<assessment>
<assessmentName>Test1</assessmentName>
<assessmentType>Coursework</assessmentType>
<assessmentWeighting>30</assessmentWeighting>
<assessmentDueDate/>
</assessment>
<assessment>
<assessmentName>Coursework</assessmentName>
<assessmentType>Coursework</assessmentType>
<assessmentWeighting>40</assessmentWeighting>
<assessmentDueDate/>
</assessment>
<assessment>
<assessmentName>Test2</assessmentName>
<assessmentType>Coursework</assessmentType>
<assessmentWeighting>30</assessmentWeighting>
<assessmentDueDate/>
</assessment>
</assessmentDetails>
</module>
</level4>
</courseStructure>
</myCourse>
(it continues level 1,level2,level3 using the same format). I simply want to display all the modules under the 'level4' hierarchy - how can i do this?/what am i doing wrong? the items are displaying just not the right ones ..
First of all you have to create one NSMutableDictionary. When you get the tag in didStartElement Method initiate this Dictionary.And also set one flag.
And in Found character method check that flag, if It is then store that tagValues and in didEndElement store all the values in this Dictionary when you find .
You can find all levels values using this.
Hope this will help you.
Use both methods:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
and
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
For parsing.