From 5612075ac791f7176535177f8e655b440426ebf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Kr=C3=A4ntzer?= Date: Sat, 15 Jun 2013 01:32:08 +0200 Subject: [PATCH] Handle namespace for elements correctly --- KissXML/DDXMLElement.m | 161 ++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 99 deletions(-) diff --git a/KissXML/DDXMLElement.m b/KissXML/DDXMLElement.m index a379820c..f4badcaf 100644 --- a/KissXML/DDXMLElement.m +++ b/KissXML/DDXMLElement.m @@ -119,71 +119,6 @@ - (id)initWithXMLString:(NSString *)string error:(NSError **)error #pragma mark Elements by name //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/** - * Helper method elementsForName and elementsForLocalName:URI: so work isn't duplicated. - * The name parameter is required, all others are optional. -**/ -- (NSArray *)_elementsForName:(NSString *)name - localName:(NSString *)localName - prefix:(NSString *)prefix - uri:(NSString *)uri -{ - // This is a private/internal method - - // Rule : !uri => match: name - // Rule : uri && hasPrefix => match: name || (localName && uri) - // Rule : uri && !hasPefix => match: name && uri - - xmlNodePtr node = (xmlNodePtr)genericPtr; - - NSMutableArray *result = [NSMutableArray array]; - - BOOL hasPrefix = [prefix length] > 0; - - const xmlChar *xmlName = [name xmlChar]; - const xmlChar *xmlLocalName = [localName xmlChar]; - const xmlChar *xmlUri = [uri xmlChar]; - - xmlNodePtr child = node->children; - while (child) - { - if (IsXmlNodePtr(child)) - { - BOOL match = NO; - - if (uri == nil) - { - match = xmlStrEqual(child->name, xmlName); - } - else - { - BOOL nameMatch = xmlStrEqual(child->name, xmlName); - BOOL localNameMatch = xmlStrEqual(child->name, xmlLocalName); - - BOOL uriMatch = NO; - if (child->ns) - { - uriMatch = xmlStrEqual(child->ns->href, xmlUri); - } - - if (hasPrefix) - match = nameMatch || (localNameMatch && uriMatch); - else - match = nameMatch && uriMatch; - } - - if (match) - { - [result addObject:[DDXMLElement nodeWithElementPrimitive:child owner:self]]; - } - } - - child = child->next; - } - - return result; -} - /** * Returns the child element nodes (as DDXMLElement objects) of the receiver that have a specified name. * @@ -199,11 +134,6 @@ - (NSArray *)elementsForName:(NSString *)name if (name == nil) return [NSArray array]; - // We need to check to see if name has a prefix. - // If it does have a prefix, we need to figure out what the corresponding URI is for that prefix, - // and then search for any elements that have the same name (including prefix) OR have the same URI. - // Otherwise we loop through the children as usual and do a string compare on the name - NSString *prefix; NSString *localName; @@ -212,19 +142,32 @@ - (NSArray *)elementsForName:(NSString *)name if ([prefix length] > 0) { xmlNodePtr node = (xmlNodePtr)genericPtr; - - // Note: We use xmlSearchNs instead of resolveNamespaceForName: because - // we want to avoid creating wrapper objects when possible. - + xmlNsPtr ns = xmlSearchNs(node->doc, node, [prefix xmlChar]); + NSString *uri = nil; if (ns) { - NSString *uri = [NSString stringWithUTF8String:((const char *)ns->href)]; - return [self _elementsForName:name localName:localName prefix:prefix uri:uri]; + uri = [NSString stringWithUTF8String:((const char *)ns->href)]; } - } - - return [self _elementsForName:name localName:localName prefix:prefix uri:nil]; + return [self elementsForLocalName:localName URI:uri]; + } else { + + NSMutableArray *result = [NSMutableArray array]; + + const xmlChar *xmlName = [name xmlChar]; + + xmlNodePtr node = (xmlNodePtr)genericPtr; + xmlNodePtr child = node->children; + while (child) + { + if (IsXmlNodePtr(child) && xmlStrEqual(child->name, xmlName)) + { + [result addObject:[DDXMLElement nodeWithElementPrimitive:child owner:self]]; + } + child = child->next; + } + return result; + } } - (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)uri @@ -233,27 +176,47 @@ - (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)uri DDXMLNotZombieAssert(); #endif - if (localName == nil) return [NSArray array]; - - // We need to figure out what the prefix is for this URI. - // Then we search for elements that are named prefix:localName OR (named localName AND have the given URI). + if (localName == nil || uri == nil) return [NSArray array]; - NSString *prefix = [self _recursiveResolvePrefixForURI:uri atNode:(xmlNodePtr)genericPtr isDefaultNamespace:NO]; - if (prefix) - { - NSString *name = [NSString stringWithFormat:@"%@:%@", prefix, localName]; - - return [self _elementsForName:name localName:localName prefix:prefix uri:uri]; - } - else - { - NSString *prefix; - NSString *realLocalName; - - [DDXMLNode getPrefix:&prefix localName:&realLocalName forName:localName]; - - return [self _elementsForName:localName localName:realLocalName prefix:prefix uri:uri]; - } + NSMutableArray *result = [NSMutableArray array]; + + xmlNodePtr node = (xmlNodePtr)genericPtr; + xmlNodePtr child = node->children; + while (child) + { + if (IsXmlNodePtr(child)) + { + NSString *childName = [NSString stringWithUTF8String:child->name]; + + NSString *childPrefix; + NSString *childLocalName; + + [DDXMLNode getPrefix:&childPrefix + localName:&childLocalName + forName:childName]; + + xmlNsPtr ns = NULL; + if (child->ns) { + ns = child->ns; + } else if ([childPrefix length] > 0) { + ns = xmlSearchNs(child->doc, child, [childPrefix xmlChar]); + } else { + ns = xmlSearchNs(child->doc, child, NULL); + } + + NSString *childURI = nil; + if (ns) { + childURI = [NSString stringWithUTF8String:((const char *)ns->href)]; + } + + if ([childURI isEqualToString:uri] && [childLocalName isEqualToString:localName]) { + [result addObject:[DDXMLElement nodeWithElementPrimitive:child owner:self]]; + } + } + child = child->next; + } + return result; + } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////