I'm trying to use RestKit (0.23.1) to parse some Atom XML as shown below:
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:ex="http://my.library.com">
<entry>
<title>Title 1</title>
<link href="http://localhost:2001/1" />
<id>urn:uuid:a6e04980-e273-11e3-8b68-0800200c9a66</id>
<updated>2013-12-21T18:30:02Z</updated>
<summary>Summary 1</summary>
<ex:thing>
<ex:name>Thing 1</ex:name>
</ex:thing>
<ex:thing>
<ex:name>Thing 2</ex:name>
</ex:thing>
</entry>
</feed>
I'm using the object mapper to map that feed into two objects. The first object represents an entry in the feed with an array of things.
@interface Entry : NSObject
@property NSString *title;
@property NSString *summary;
@property NSMutableArray *things;
@end
The NSMutableArray is to contain the collection of things.
@interface Thing : NSObject
@property NSString *name;
@end
And finally the RestKit code to glue this all together is here:
- (void) parseAtomThings {
[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:@"application/atom+xml"];
RKObjectMapping *entryMapping = [RKObjectMapping mappingForClass:[Entry class]];
[entryMapping addAttributeMappingsFromDictionary:@{
@"title.text" : @"title",
@"summary.text" : @"summary"
}];
RKObjectMapping *thingMapping = [RKObjectMapping mappingForClass:[Thing class]];
[thingMapping addAttributeMappingsFromDictionary:@{
@"name.text" : @"name"
}];
// TODO - how do I get this to map to ex:thing?
[entryMapping addRelationshipMappingWithSourceKeyPath:@"thing" mapping:thingMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entryMapping method:RKRequestMethodGET pathPattern:nil
keyPath:@"feed.entry" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:2001/library.xml"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
for(Entry *entry in [result array]) {
NSLog(@"%@", entry.description);
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Failed with error: %@", [error localizedDescription]);
}];
[operation start];
}
Upon execution, the Entry object's title and summary properties are populated. However, the NSMutableArray of things isn't populated and is nil.
I'm sure the magic I'm looking for is around this line:
[entryMapping addRelationshipMappingWithSourceKeyPath:@"thing" mapping:thingMapping];
But I can't figure out how to correctly specify the the list of maps to the thing property on the Entry class.
The logging is here:
2014-05-23 23:06:05.457 TestApp[61282:3303] D restkit.object_mapping:RKMappingOperation.m:859 Starting mapping operation...
2014-05-23 23:06:05.457 TestApp[61282:3303] T restkit.object_mapping:RKMappingOperation.m:860 Performing mapping operation: <RKMappingOperation 0xbe3b4b0> for 'Entry' object. Mapping values from object {
"ex:thing" = (
{
"ex:name" = {
text = "Thing 1";
};
text = "";
},
{
"ex:name" = {
text = "Thing 2";
};
text = "";
}
);
id = {
text = "urn:uuid:a6e04980-e273-11e3-8b68-0800200c9a66";
};
link = {
href = "http://localhost:2001/1";
text = "";
};
summary = {
text = "Summary 1";
};
text = "";
title = {
text = "Title 1";
};
updated = {
text = "2013-12-21T18:30:02Z";
};
} to object <Entry: 0xbe39e00> with object mapping (null)
2014-05-23 23:06:05.458 TestApp[61282:3303] D restkit.object_mapping:RKMappingOperation.m:728 Did not find mappable relationship value keyPath 'thing'
2014-05-23 23:06:05.459 TestApp[61282:3303] T restkit.object_mapping:RKMappingOperation.m:438 Found transformable value at keyPath 'summary.text'. Transforming from class '__NSCFString' to 'NSString'
2014-05-23 23:06:05.459 TestApp[61282:3303] T restkit.object_mapping:RKMappingOperation.m:453 Mapping attribute value keyPath 'summary.text' to 'summary'
2014-05-23 23:06:05.459 TestApp[61282:3303] T restkit.object_mapping:RKMappingOperation.m:469 Mapped attribute value from keyPath 'summary.text' to 'summary'. Value: Summary 1
2014-05-23 23:06:05.459 TestApp[61282:e03] D restkit.object_mapping:RKPropertyInspector.m:131 Cached property inspection for Class 'Entry': {
summary = {
isPrimitive = 0;
keyValueCodingClass = NSString;
name = summary;
};
things = {
isPrimitive = 0;
keyValueCodingClass = NSMutableArray;
name = things;
};
title = {
isPrimitive = 0;
keyValueCodingClass = NSString;
name = title;
};
}
2014-05-23 23:06:05.460 TestApp[61282:3303] T restkit.object_mapping:RKMappingOperation.m:438 Found transformable value at keyPath 'title.text'. Transforming from class '__NSCFString' to 'NSString'
2014-05-23 23:06:05.460 TestApp[61282:3303] T restkit.object_mapping:RKMappingOperation.m:453 Mapping attribute value keyPath 'title.text' to 'title'
2014-05-23 23:06:05.461 TestApp[61282:3303] T restkit.object_mapping:RKMappingOperation.m:469 Mapped attribute value from keyPath 'title.text' to 'title'. Value: Title 1
2014-05-23 23:06:05.461 TestApp[61282:3303] D restkit.object_mapping:RKMappingOperation.m:928 Finished mapping operation successfully...
2014-05-23 23:06:05.461 TestApp[61282:3303] D restkit.object_mapping:RKMapperOperation.m:403 Finished performing object mapping. Results: {
"feed.entry" = "<Entry: 0xbe39e00>";
}
The logging clearly states:
014-05-23 23:06:05.458 TestApp[61282:3303] D restkit.object_mapping:RKMappingOperation.m:728 Did not find mappable relationship value keyPath 'thing'
I'm guessing I can't see the wood for the trees and have missed something really obvious. Any help is much appreciated.
You are missing the ex:
from your key paths.
To cater for this you will need to create a relationship mapping and add it (with relationshipMappingFromKeyPath:toKeyPath:withMapping:
) instead of using the convenience method addRelationshipMappingWithSourceKeyPath:mapping:
(because the source and destination paths are different).
This same issue extends to the name where you will need to change @"name.text"
to @"ex:name.text"
.