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?
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:
- 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
.
- In
parser:foundCharacters:
, append the found characters to contentOfCurrentXMLProperty
.
- 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
.
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.