Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing deep XML structure using RESTKit

I am sold on RESTKit's potential -- it sounds awesome.

Unfortunately, all of the examples I've been able to find revolve around parsing JSON, and parsing relatively "flat" JSON at that. The unfortunately reality of the world is that there's lots of XML, and a lot of it is ugly.

Particularly, I cannot seem to find any good examples of parsing a deeply nested XML structure.

I think my failing is in understanding key paths, and I'm hoping the answer to this question will become a canonical example for others who are facing this problem.

Let's go with a contrived example. Consider the following XML:

<?xml version="1.0"?> 
<old_lady fate="perhaps she'll die!"> 
  <bird reason = "to catch the spider"> 
    <spider reason="to catch the fly"> 
      <fly reason="why oh why?" action="swallowed" name="Al"/> 
      <fly reason="why oh why?" action="swallowed" name="Bob"/> 
      <fly reason="why oh why?" action="swallowed" name="Cory"/> 
      <fly reason="why oh why?" action="swallowed" name="Dan"/> 
      <fly reason="why oh why?" action="swallowed" name="Edgar"/> 
    </spider> 
  </bird> 
</old_lady>

Let's say I want to get out of this a list of Fly objects:

@interface Fly : NSObject 
@property (retain) NSString *reason; 
@property (retain) NSString *action; 
@property (retain) NSString *name; 
@end 

So I had thought I'd do something like this:

[RKObjectManager objectManagerWithBaseURL:[NSURL 
URLWithString:@"http://some.server.com"]];

RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Fly class]]; 
[mapping mapKeyPath:@"reason" toAttribute:@"reason"]; 
[mapping mapKeyPath:@"action" toAttribute:@"action"]; 
[mapping mapKeyPath:@"name" toAttribute:@"name"];

[RKObjectManager.sharedManager.mappingProvider setMapping:mapping
forKeyPath:@"//old_lady/bird/spider/fly"]; 

[[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/path/to/rhyme.xml" 
                                                  delegate:self]; 

However, this gets me:

Encountered errors during mapping: Could not find an object mapping for keyPath: '' 

I'm sure the problem is my '//old_lady/bird/spider/fly' key path, but I just can't find any similar examples to model a solution after. Halp?

like image 312
cell Avatar asked Jan 17 '23 17:01

cell


1 Answers

I feel like a fool. After being stuck on this for more than a day, I discovered the solution only moments after posting to stackoverflow.

My problem is that I confused the notion of an XPath with the Objective-C notion of a key-value coding key path.

Indeed, using this:

[RKObjectManager.sharedManager.mappingProvider setMapping:mapping 
forKeyPath:@"old_lady.bird.spider.fly"]; 

and logging the results thusly:

- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects: 
(NSArray *)objects 
{ 
    for (Fly *fly in objects) 
    { 
        NSLog(@"%@, %@, %@", fly.reason, fly.action, fly.name); 
    } 
} 

I see this in the console, just as expected:

2012-05-08 14:08:50.173 Foo[26922:207] why oh why?, swallowed, Al 
2012-05-08 14:08:50.173 Foo[26922:207] why oh why?, swallowed, Bob 
2012-05-08 14:08:50.175 Foo[26922:207] why oh why?, swallowed, Cory 
2012-05-08 14:08:50.176 Foo[26922:207] why oh why?, swallowed, Dan 
2012-05-08 14:08:50.176 Foo[26922:207] why oh why?, swallowed, Edgar 
like image 159
cell Avatar answered Jan 26 '23 02:01

cell