views:

682

answers:

2

I am trying to figure out NSXMLParser for my iPhone app and while I generally understand how it works, I am still a little confused about how to extract the values I need.

The XML result that I am parsing is very basic. it is like so:

<start>
 <status>300</status>
 <record>
  <title>The Title</title>
  <content>Some content</content>
 </record>
</start>

I need to do 3 things: Get the value of status. Get the value of content from the first record. There may come a response that offers multiple "record" elements so I need to only get the first.

I can't figure out how to simply do that. Most all of the examples I have seen involve creating a separate object to populate this data into and I can't see that being necessary for 2 values. Can anyone tell me how to pull these 2 pieces of data out and only for the first record?

+2  A: 

The first thing that happens when the NSXMLParser encounters an XML tag is that the delegate method parser:didStartElement:namespaceURI:qualifiedName:attributes: is called; you'll probably only need to use the elementName variable here. Then, the XML parser reads the characters in the tag and calls parser:foundCharacters: with the contents. Finally parser:didEndElement:namespaceURI:qualifiedName is called.

The approach that I've taken, as Apple uses in the SeismicXML examlple, is to use the methods as follows:

  1. In parser:didStartElement:namespaceURI:qualifiedName:attributes:, compare the string of the element name to a known value to see if it's a string you care about. If so, then set an instance variable (an NSMutableString; I'll call it contentOfCurrentXMLProperty) to an empty string. Otherwise set it to nil.
  2. In parser:foundCharacters:, append the found characters to contentOfCurrentXMLProperty.
  3. In parser:didEndElement:namespaceURI:qualifiedName, assign the value of contentofCurrentXMLProperty to whatever the appropriate variable is.

See the SeismicXML example for more information.

A couple of things about your specific case: first, since the XML parser only returns strings, you'll need to convert the string to an integer (or whatever data type you're using) for status.

Second, since you only want the first value for record, in parser:didStartElement:... I'd set up a BOOL that flags whether you've already seen a record tag before and, if so, set contentOfCurrentXMLProperty to nil.

Jeff Kelley
+2  A: 

Keeping in mind that NSXMLParser is SAX-like event-based parser, you must set up your parser, start it and listen for key events.

Set the parser up:

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[parser setDelegate:self];
[parser parse];

Override these methods:

– parser:didStartElement:namespaceURI:qualifiedName:attributes:
– parser:didEndElement:namespaceURI:qualifiedName:
– parser:foundCharacters:

Your function must basically say:

  • When you reach the next start of a tag:

-(void)parser: didStartElement:(NSString *) namespaceURI:(NSString *) qualifiedName:(NSString *) attributes:(NSDictionary *)

  • If that tag's name is "status":

[elementName isEqualToString:@"status"]

  • Give me the tag's string data:

- (void)parser:(NSXMLParser *) foundCharacters:(NSString *)

...

[<your statusValueHolder as NSMutableString> appendString:<foundCharacters' parameter>]

...

You can apply the same logic for the other case (search for the first start of a tag named "record", abort on reaching the end of tag, named "record", etc)

Have a look at this and try it at home: Make NSXMLParser your friend.. Also see API Reference Docs for NSXMLParser for additional delegate methods for NSXMLParser's delegate.

Dimitar Dimitrov
Thanks to both of you. I finally got it to work.
SonnyBurnette