Question

First, please excuse the terminology if it's not correct. I'm toying with parsing an XML feed from the San Francisco BART system into a UITableView, in an effort to see how parsing works. Parsing a simple feed as below is pretty straight forward.

<?xml version="1.0" encoding="utf-8" ?> 
<root>
  <uri><![CDATA[ http://api.bart.gov/api/sched.aspx?cmd=special ]]></uri>
  <holidays>
    <holiday>
      <name>New Year's Day (2009)</name> 
      <date>01/01/2009</date> 
      <schedule_type>Sunday</schedule_type> 
    </holiday>
    <holiday>
      <name>Presidents' Day</name> 
      <date>02/16/2009</date> 
      <schedule_type>Saturday</schedule_type> 
    </holiday>

I'm feeling pretty confident there. The problem is now I've moved to a more complex format which looks as follows.

<?xml version="1.0" encoding="utf-8" ?> 
<root>
  <uri><![CDATA[ http://api.bart.gov/api/etd.aspx?cmd=etd&orig=RICH ]]></uri>
  <date>03/30/2011</date> 
  <time>02:43:27 PM PDT</time> 
  <station>
    <name>Richmond</name> 
    <abbr>RICH</abbr> 
  <etd>
    <destination>Fremont</destination> 
    <abbreviation>FRMT</abbreviation> 
    <estimate>
      <minutes>5</minutes> 
      <platform>2</platform> 
      <direction>South</direction> 
      <length>6</length> 
      <color>ORANGE</color> 
      <hexcolor>#ff9933</hexcolor> 
      <bikeflag>1</bikeflag> 
    </estimate>
    <estimate>
    <minutes>20</minutes> 
      <platform>2</platform> 
      <direction>South</direction> 
      <length>6</length> 
      <color>ORANGE</color> 
      <hexcolor>#ff9933</hexcolor> 
      <bikeflag>1</bikeflag> 
    </estimate>
  </etd>
  <etd>
    <destination>Millbrae</destination> 
    <abbreviation>MLBR</abbreviation> 
    <estimate>
      <minutes>Leaving</minutes> 
      <platform>2</platform> 
      <direction>South</direction> 
      <length>10</length> 
      <color>RED</color> 
      <hexcolor>#ff0000</hexcolor> 
      <bikeflag>1</bikeflag> 
    </estimate>
  </etd>
 </station>
 <message /> 
</root>

The actual problem I'm having is how to build the array that populates my tableview in the didStart and didEnd methods since this is a more complex structure. What I have is as follows (the ending trial before I got frustrated enough to come ask for help) and is quite far from correct

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {


element = elementName;

if ([element isEqualToString:@"station"]) {

    station = [[NSMutableDictionary alloc] init];
    name   = [[NSMutableString alloc] init];

}

if ([element isEqualToString:@"etd"]) {

    etd    = [[NSMutableDictionary alloc] init];
    destination   = [[NSMutableString alloc] init];

}

if ([element isEqualToString:@"estimate"]) {

    estimate    = [[NSMutableDictionary alloc] init];
    minutes   = [[NSMutableString alloc] init];
}

}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

if ([elementName isEqualToString:@"station"]) {
    [station setObject:name forKey:@"name"];

    [data addObject:[station copy]];

}

if ([elementName isEqualToString:@"etd"]) {
    [etd setObject:destination forKey:@"destination"];        
    //[data addObject:[etd copy]];

}

if ([elementName isEqualToString:@"estimate"]) {
    [estimate setObject:minutes forKey:@"minutes"];
    //[data addObject:[estimate copy]];
}
}

I understand what I have above is creating a separate array for each element. The end goal is to drill down from station name, to destination, to departing in "x minutes". Also I'm not using XCODE for this where most of the magic happens for me, there's plenty tutorials for parsing simple XML, SO has lots of questions relating to simple structures as well with lots suggesting to use another parser. These are not options for me, I'm restricted to pure code without XCODE or IB. The end question here is how would I go about building my final array to allow drilling down the data structure?

Was it helpful?

Solution 2

Looks like walking away and coming back fresh minded does wonders still. This is the solution I came up with. Not too hard.

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {


element = elementName;

if ([element isEqualToString:@"station"]) {

    stationArray = [[NSMutableArray alloc] init];

    station = [[NSMutableDictionary alloc] init];
    name   = [[NSMutableString alloc] init];

}

else if ([element isEqualToString:@"etd"]) {

    destinationArray    = [[NSMutableArray alloc] init];
    destination   = [[NSMutableString alloc] init];

}

else if ([element isEqualToString:@"estimate"]) {

    estimateArray    = [[NSMutableArray alloc] init];
    minutes   = [[NSMutableString alloc] init];


}

}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

///// Add Arrays to Dictionary, then Copy back to Array that sorts the Table

if ([elementName isEqualToString:@"station"]) {
    [station setObject:name forKey:@"name"];
    [station setObject:destinationArray forKey:@"destination"];
    [station setObject:estimateArray forKey:@"minutes"];
    [data addObject:[station copy]];

}

///// Add Destinations to an array

else if ([elementName isEqualToString:@"etd"]) {
    [destinationArray addObject:destination];


}

///// Add minutes to an array

else if ([elementName isEqualToString:@"estimate"]) {
    [estimateArray addObject:minutes];


}

}

OTHER TIPS

This isn't a direct answer, but, from my experience the NSXMLParser gets really difficult the deeper you have to dig into xml, my solution was always using XMLDictionary. Granted this does not solve your problem BUT the XMLDictionary does use the NSXMLParser, so if you download the files, you will be able to see how they handled the more complex XML structures.

XMLDictionary example

remember to #import "XMLDictionary.h"

NSString *googleString = @"http://www.google.com/"; // your xml url
NSDictionary *xml = [NSDictionary dictionaryWithXMLString:googleString];

Then you can dig through the dictionary to retrieve the data you would like.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top