Skip to content
Browse files

Added new unit tests for XML support and merged fixes from @Edubits p…

…ull request #262 and changes from @cellcortex #314. Attributes and nesting should behave better. closes #262, #314
  • Loading branch information...
1 parent 30826a0 commit 3832ec7b9fcd61ad4d713344c32a8d146da4395d @blakewatters blakewatters committed
View
45 Code/Support/Parsers/XML/RKXMLParserLibXML.m
@@ -2,7 +2,7 @@
// RKXMLParserLibXML.m
//
// Created by Jeremy Ellison on 2011-02-28.
-// Copyright (c) 2011 __MyCompanyName__. All rights reserved.
+// Copyright (c) 2011 RestKit. All rights reserved.
//
#import <libxml2/libxml/parser.h>
@@ -22,7 +22,14 @@ - (id)parseNode:(xmlNode*)node {
if ([val isKindOfClass:[NSString class]]) {
id oldVal = [attrs valueForKey:nodeName];
if (nil == oldVal) {
- [attrs setValue:val forKey:nodeName];
+ // Assume that empty strings are irrelevant and go for an attribute-collection instead
+ if ([val length] == 0) {
+ val = [NSMutableDictionary dictionary];
+ NSDictionary* elem = [NSDictionary dictionaryWithObject:val forKey:nodeName];
+ [nodes addObject:elem];
+ } else {
+ [attrs setValue:val forKey:nodeName];
+ }
} else if ([oldVal isKindOfClass:[NSMutableArray class]]) {
[oldVal addObject:val];
} else {
@@ -35,20 +42,25 @@ - (id)parseNode:(xmlNode*)node {
[nodes addObject:attrs];
}
} else {
- xmlElement* element = (xmlElement*)currentNode;
- xmlAttribute* currentAttribute = NULL;
- for (currentAttribute = (xmlAttribute*)element->attributes; currentAttribute; currentAttribute = (xmlAttribute*)currentAttribute->next) {
- NSString* name = [NSString stringWithCString:(char*)currentAttribute->name encoding:NSUTF8StringEncoding];
- xmlChar* str = xmlNodeGetContent((xmlNode*)currentAttribute);
- NSString* valattr = [NSString stringWithCString:(char*)str encoding:NSUTF8StringEncoding];
- xmlFree(str);
- [val setValue:valattr forKey:name];
- }
-
- NSMutableDictionary* elem = [NSMutableDictionary dictionaryWithObject:val forKey:nodeName];
-
+ NSDictionary* elem = [NSDictionary dictionaryWithObject:val forKey:nodeName];
[nodes addObject:elem];
}
+ xmlElement* element = (xmlElement*)currentNode;
+ xmlAttribute* currentAttribute = NULL;
+ for (currentAttribute = (xmlAttribute*)element->attributes; currentAttribute; currentAttribute = (xmlAttribute*)currentAttribute->next) {
+ NSString* name = [NSString stringWithCString:(char*)currentAttribute->name encoding:NSUTF8StringEncoding];
+ xmlChar* str = xmlNodeGetContent((xmlNode*)currentAttribute);
+ NSString* value = [NSString stringWithCString:(char*)str encoding:NSUTF8StringEncoding];
+ xmlFree(str);
+ [attrs setValue:value forKey:name];
+ if ([val isKindOfClass:[NSDictionary class]]) {
+ // Add attributes as properties of the class
+ [val setObject:value forKey:name];
+ } else if (![nodes containsObject:attrs]) {
+ // Only add attributes to nodes if there actually is one.
+ [nodes addObject:attrs];
+ }
+ }
} else if (currentNode->type == XML_TEXT_NODE) {
xmlChar* str = xmlNodeGetContent(currentNode);
NSString* part = [NSString stringWithCString:(const char*)str encoding:NSUTF8StringEncoding];
@@ -64,7 +76,6 @@ - (id)parseNode:(xmlNode*)node {
if ([nodes count] == 0) {
return @"";
}
-
if (YES || [nodes containsObject:attrs]) {
// We have both attributes and children. merge everything together.
NSMutableDictionary* results = [NSMutableDictionary dictionary];
@@ -91,7 +102,7 @@ - (NSDictionary*)parseXML:(NSString*)xml {
xmlParserCtxtPtr ctxt; /* the parser context */
xmlDocPtr doc; /* the resulting document tree */
id result = nil;;
-
+
/* create a parser context */
ctxt = xmlNewParserCtxt();
if (ctxt == NULL) {
@@ -132,4 +143,4 @@ - (NSString*)stringFromObject:(id)object error:(NSError **)error {
return nil;
}
-@end
+@end
View
8 RestKit.xcodeproj/project.pbxproj
@@ -247,6 +247,8 @@
25A1CB52138419D900A7D5C9 /* libRestKitXMLParserLibxml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 25BD43BD1340315800DBACDD /* libRestKitXMLParserLibxml.a */; };
25AA85D613B1065000A95E2A /* RKObjectLoaderSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 25D1983F1368A9CE0090B617 /* RKObjectLoaderSpec.m */; };
25ACF1AD13BB9D490067B380 /* RKURLSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 25ACF1AC13BB9D480067B380 /* RKURLSpec.m */; };
+ 25B72A5813FBEDEE009A340D /* container_attributes.xml in Resources */ = {isa = PBXBuildFile; fileRef = 25B72A5713FBEDEE009A340D /* container_attributes.xml */; };
+ 25B72A5A13FBF13B009A340D /* attributes_without_text_content.xml in Resources */ = {isa = PBXBuildFile; fileRef = 25B72A5913FBF13B009A340D /* attributes_without_text_content.xml */; };
25BA443513ABB34900ADC7D0 /* tab_data.xml in Resources */ = {isa = PBXBuildFile; fileRef = 25915ACF13A2E82200EA63B0 /* tab_data.xml */; };
25C66B0113A43A4900FEA8CB /* RKFilterableObjectLoaderTTModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 25C66AF913A43A4900FEA8CB /* RKFilterableObjectLoaderTTModel.h */; settings = {ATTRIBUTES = (Public, ); }; };
25C66B0213A43A4900FEA8CB /* RKFilterableObjectLoaderTTModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 25C66AFA13A43A4900FEA8CB /* RKFilterableObjectLoaderTTModel.m */; };
@@ -661,6 +663,8 @@
25A1CB49138413DF00A7D5C9 /* RKMIMETypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKMIMETypes.h; sourceTree = "<group>"; };
25A1CB4A138413E000A7D5C9 /* RKMIMETypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKMIMETypes.m; sourceTree = "<group>"; };
25ACF1AC13BB9D480067B380 /* RKURLSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKURLSpec.m; sourceTree = "<group>"; };
+ 25B72A5713FBEDEE009A340D /* container_attributes.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = container_attributes.xml; sourceTree = "<group>"; };
+ 25B72A5913FBF13B009A340D /* attributes_without_text_content.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = attributes_without_text_content.xml; sourceTree = "<group>"; };
25BD43BD1340315800DBACDD /* libRestKitXMLParserLibxml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKitXMLParserLibxml.a; sourceTree = BUILT_PRODUCTS_DIR; };
25C66AF913A43A4900FEA8CB /* RKFilterableObjectLoaderTTModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKFilterableObjectLoaderTTModel.h; sourceTree = "<group>"; };
25C66AFA13A43A4900FEA8CB /* RKFilterableObjectLoaderTTModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKFilterableObjectLoaderTTModel.m; sourceTree = "<group>"; };
@@ -1329,6 +1333,8 @@
isa = PBXGroup;
children = (
25915ACF13A2E82200EA63B0 /* tab_data.xml */,
+ 25B72A5713FBEDEE009A340D /* container_attributes.xml */,
+ 25B72A5913FBF13B009A340D /* attributes_without_text_content.xml */,
);
path = XML;
sourceTree = "<group>";
@@ -1994,6 +2000,8 @@
252CF8BB13E255E20093BBD6 /* girl.json in Resources */,
252CF8BD13E255EB0093BBD6 /* mixed.json in Resources */,
250F060C13E3B2F900FAAFBF /* friends.json in Resources */,
+ 25B72A5813FBEDEE009A340D /* container_attributes.xml in Resources */,
+ 25B72A5A13FBF13B009A340D /* attributes_without_text_content.xml in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
5 Specs/Fixtures/XML/attributes_without_text_content.xml
@@ -0,0 +1,5 @@
+<exchange_rate type="XML_RATE_TYPE_EBNK_MIDDLE" valid_from="2011-08-03 00:00:00.0">
+ <currency name="AUD" quota="1" rate="18.416"/>
+ <currency name="HRK" quota="1" rate="3.25017"/>
+ <currency name="DKK" quota="1" rate="3.251"/>
+</exchange_rate>
View
8 Specs/Fixtures/XML/container_attributes.xml
@@ -0,0 +1,8 @@
+<elements>
+ <element attribute="1">
+ <subelement>text</subelement>
+ </element>
+ <element attribute="2">
+ <subelement>text2</subelement>
+ </element>
+</elements>
View
47 Specs/Support/RKXMLParserSpec.m
@@ -65,7 +65,6 @@ - (void)itShouldMapXML {
[mapping mapAttributes:@"title", @"summary", nil];
RKObjectMappingProvider* provider = [[RKObjectMappingProvider alloc] init];
id data = RKSpecParseFixture(@"tab_data.xml");
- NSLog(@"%@", data);
assertThat([data valueForKeyPath:@"tabdata.item"], is(instanceOf([NSArray class])));
[provider setMapping:mapping forKeyPath:@"tabdata.item"];
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:data mappingProvider:provider];
@@ -75,4 +74,50 @@ - (void)itShouldMapXML {
assertThatInt([[data valueForKeyPath:@"tabdata.item"] count], is(equalToInt(2)));
}
+- (void)itShouldParseXMLWithAttributes {
+ NSString* XML = RKSpecReadFixture(@"container_attributes.xml");
+ RKXMLParserLibXML* parser = [[RKXMLParserLibXML new] autorelease];
+ NSDictionary* result = [parser parseXML:XML];
+ assertThat(result, is(instanceOf([NSDictionary class])));
+ NSArray* elements = [[result objectForKey:@"elements"] objectForKey:@"element"];
+ assertThat(elements, isNot(nilValue()));
+ assertThat(elements, is(instanceOf([NSArray class])));
+ assertThat(elements, hasCountOf(2));
+ NSDictionary* firstElement = [elements objectAtIndex:0];
+ assertThat([firstElement objectForKey:@"attribute"], is(equalTo(@"1")));
+ assertThat([firstElement objectForKey:@"subelement"], is(equalTo(@"text")));
+ NSDictionary* secondElement = [elements objectAtIndex:1];
+ assertThat([secondElement objectForKey:@"attribute"], is(equalTo(@"2")));
+ assertThat([secondElement objectForKey:@"subelement"], is(equalTo(@"text2")));
+}
+
+- (void)itShouldParseXMLWithAttributesInTextNodes {
+ NSString* XML = RKSpecReadFixture(@"attributes_without_text_content.xml");
+ RKXMLParserLibXML* parser = [[RKXMLParserLibXML new] autorelease];
+ NSDictionary* result = [parser parseXML:XML];
+ NSDictionary* exchangeRate = [result objectForKey:@"exchange_rate"];
+ assertThat(exchangeRate, is(notNilValue()));
+ assertThat([exchangeRate objectForKey:@"type"], is(equalTo(@"XML_RATE_TYPE_EBNK_MIDDLE")));
+ assertThat([exchangeRate objectForKey:@"valid_from"], is(equalTo(@"2011-08-03 00:00:00.0")));
+ NSArray* currency = [exchangeRate objectForKey:@"currency"];
+ assertThat(currency, hasCountOf(3));
+ NSDictionary* firstCurrency = [currency objectAtIndex:0];
+ assertThat(firstCurrency, is(instanceOf([NSDictionary class])));
+ assertThat([firstCurrency objectForKey:@"name"], is(equalTo(@"AUD")));
+ assertThat([firstCurrency objectForKey:@"quota"], is(equalTo(@"1")));
+ assertThat([firstCurrency objectForKey:@"rate"], is(equalTo(@"18.416")));
+
+ NSDictionary* secondCurrency = [currency objectAtIndex:1];
+ assertThat(secondCurrency, is(instanceOf([NSDictionary class])));
+ assertThat([secondCurrency objectForKey:@"name"], is(equalTo(@"HRK")));
+ assertThat([secondCurrency objectForKey:@"quota"], is(equalTo(@"1")));
+ assertThat([secondCurrency objectForKey:@"rate"], is(equalTo(@"3.25017")));
+
+ NSDictionary* thirdCurrency = [currency objectAtIndex:2];
+ assertThat(thirdCurrency, is(instanceOf([NSDictionary class])));
+ assertThat([thirdCurrency objectForKey:@"name"], is(equalTo(@"DKK")));
+ assertThat([thirdCurrency objectForKey:@"quota"], is(equalTo(@"1")));
+ assertThat([thirdCurrency objectForKey:@"rate"], is(equalTo(@"3.251")));
+}
+
@end

0 comments on commit 3832ec7

Please sign in to comment.
Something went wrong with that request. Please try again.