Skip to content

Commit

Permalink
Minor optimizations and formatting tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
robbiehanson committed Nov 2, 2011
1 parent 406159c commit b2f387f
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 144 deletions.
4 changes: 2 additions & 2 deletions KissXML/DDXML.h
Expand Up @@ -81,7 +81,7 @@
// Heap corruption is one of the worst problems to track down.
// So to help out, the library provides a debugging macro to track down these problems.
// That is, if you invalidate the write-access thread-unsafe rule,
// this macro will tell you when you're trying to access a no-dangling pointer.
// this macro will tell you when you're trying to access a now-dangling pointer.
//
// How does it work?
// Well everytime a DDXML wrapper object is created atop a libxml structure,
Expand All @@ -90,6 +90,6 @@
// So everytime a DDXML wrapper objects is about to dereference it's pointer,
// it first ensures the linkage still exists in the table.
//
// The debugging macro adds a significant amount of overhead, and shouldn't be enabled on production builds.
// The debugging macro adds a significant amount of overhead, and should NOT be enabled on production builds.

#define DDXML_DEBUG_MEMORY_ISSUES 0
255 changes: 144 additions & 111 deletions KissXML/DDXMLElement.m
Expand Up @@ -105,6 +105,71 @@ - (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.
*
Expand All @@ -125,25 +190,30 @@ - (NSArray *)elementsForName:(NSString *)name
// 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 = [[self class] prefixForName:name];
NSString *prefix;
NSString *localName;

[DDXMLNode getPrefix:&prefix localName:&localName forName: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]);
if (ns != NULL)
if (ns)
{
NSString *uri = [NSString stringWithUTF8String:((const char *)ns->href)];
return [self _elementsForName:name uri:uri];
return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
}

// Note: We used xmlSearchNs instead of resolveNamespaceForName: because
// we want to avoid creating wrapper objects when possible.
}

return [self _elementsForName:name uri:nil];
return [self _elementsForName:name localName:localName prefix:prefix uri:nil];
}

- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI
- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)uri
{
#if DDXML_DEBUG_MEMORY_ISSUES
DDXMLNotZombieAssert();
Expand All @@ -154,75 +224,22 @@ - (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI
// 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).

NSString *prefix = [self _recursiveResolvePrefixForURI:URI atNode:(xmlNodePtr)genericPtr];
if (prefix != nil)
NSString *prefix = [self _recursiveResolvePrefixForURI:uri atNode:(xmlNodePtr)genericPtr];
if (prefix)
{
NSString *name = [NSString stringWithFormat:@"%@:%@", prefix, localName];

return [self _elementsForName:name uri:URI];
return [self _elementsForName:name localName:localName prefix:prefix uri:uri];
}
else
{
return [self _elementsForName:localName uri:URI];
}
}

/**
* Helper method elementsForName and elementsForLocalName:URI: so work isn't duplicated.
* The name parameter is required, URI is optional.
**/
- (NSArray *)_elementsForName:(NSString *)name uri:(NSString *)uri
{
// This is a private/internal method

// Supplied: name, !uri : match: name
// Supplied: p:name, uri : match: p:name || (name && uri)
// Supplied: name, uri : match: name && uri

NSMutableArray *result = [NSMutableArray array];

xmlNodePtr node = (xmlNodePtr)genericPtr;

BOOL hasPrefix = [[[self class] prefixForName:name] length] > 0;
NSString *localName = [[self class] localNameForName:name];

xmlNodePtr child = node->children;
while (child != NULL)
{
if (child->type == XML_ELEMENT_NODE)
{
BOOL match = NO;
if (uri == nil)
{
match = xmlStrEqual(child->name, [name xmlChar]);
}
else
{
BOOL nameMatch = xmlStrEqual(child->name, [name xmlChar]);
BOOL localNameMatch = xmlStrEqual(child->name, [localName xmlChar]);

BOOL uriMatch = NO;
if (child->ns != NULL)
{
uriMatch = xmlStrEqual(child->ns->href, [uri xmlChar]);
}

if (hasPrefix)
match = nameMatch || (localNameMatch && uriMatch);
else
match = nameMatch && uriMatch;
}

if (match)
{
[result addObject:[DDXMLElement nodeWithElementPrimitive:child owner:self]];
}
}
NSString *prefix;
NSString *realLocalName;

child = child->next;
[DDXMLNode getPrefix:&prefix localName:&realLocalName forName:localName];

return [self _elementsForName:localName localName:realLocalName prefix:prefix uri:uri];
}

return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -234,10 +251,9 @@ - (BOOL)_hasAttributeWithName:(NSString *)name
// This is a private/internal method

xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
if (attr != NULL)
if (attr)
{
const xmlChar *xmlName = [name xmlChar];

do
{
if (xmlStrEqual(attr->name, xmlName))
Expand All @@ -246,7 +262,7 @@ - (BOOL)_hasAttributeWithName:(NSString *)name
}
attr = attr->next;

} while (attr != NULL);
} while (attr);
}

return NO;
Expand All @@ -269,10 +285,9 @@ - (void)_removeAllAttributes
- (void)_removeAttributeForName:(NSString *)name
{
xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
if (attr != NULL)
if (attr)
{
const xmlChar *xmlName = [name xmlChar];

do
{
if (xmlStrEqual(attr->name, xmlName))
Expand All @@ -282,7 +297,7 @@ - (void)_removeAttributeForName:(NSString *)name
}
attr = attr->next;

} while(attr != NULL);
} while(attr);
}
}

Expand Down Expand Up @@ -344,33 +359,36 @@ - (DDXMLNode *)attributeForName:(NSString *)name
DDXMLNotZombieAssert();
#endif

const xmlChar *attrName = [name xmlChar];

xmlAttrPtr attr = ((xmlNodePtr)genericPtr)->properties;
while (attr != NULL)
if (attr)
{
if (attr->ns && attr->ns->prefix)
const xmlChar *xmlName = [name xmlChar];
do
{
// If the attribute name was originally something like "xml:quack",
// then attr->name is "quack" and attr->ns->prefix is "xml".
//
// So if the user is searching for "xml:quack" we need to take the prefix into account.
// Note that "xml:quack" is what would be printed if we output the attribute.

if (xmlStrQEqual(attr->ns->prefix, attr->name, attrName))
if (attr->ns && attr->ns->prefix)
{
return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
// If the attribute name was originally something like "xml:quack",
// then attr->name is "quack" and attr->ns->prefix is "xml".
//
// So if the user is searching for "xml:quack" we need to take the prefix into account.
// Note that "xml:quack" is what would be printed if we output the attribute.

if (xmlStrQEqual(attr->ns->prefix, attr->name, xmlName))
{
return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
}
}
}
else
{
if (xmlStrEqual(attr->name, attrName))
else
{
return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
if (xmlStrEqual(attr->name, xmlName))
{
return [DDXMLAttributeNode nodeWithAttrPrimitive:attr owner:self];
}
}
}

attr = attr->next;

attr = attr->next;

} while (attr);
}
return nil;
}
Expand Down Expand Up @@ -542,13 +560,18 @@ - (DDXMLNode *)namespaceForPrefix:(NSString *)prefix
else
{
xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
while (ns != NULL)
if (ns)
{
if (xmlStrEqual(ns->prefix, [prefix xmlChar]))
const xmlChar *xmlPrefix = [prefix xmlChar];
do
{
return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self];
}
ns = ns->next;
if (xmlStrEqual(ns->prefix, xmlPrefix))
{
return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:(xmlNodePtr)genericPtr owner:self];
}
ns = ns->next;

} while (ns);
}
}

Expand Down Expand Up @@ -583,13 +606,18 @@ - (DDXMLNode *)_recursiveResolveNamespaceForPrefix:(NSString *)prefix atNode:(xm
if (nodePtr == NULL) return nil;

xmlNsPtr ns = nodePtr->nsDef;
while (ns != NULL)
if (ns)
{
if (xmlStrEqual(ns->prefix, [prefix xmlChar]))
const xmlChar *xmlPrefix = [prefix xmlChar];
do
{
return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:nodePtr owner:self];
}
ns = ns->next;
if (xmlStrEqual(ns->prefix, xmlPrefix))
{
return [DDXMLNamespaceNode nodeWithNsPrimitive:ns nsParent:nodePtr owner:self];
}
ns = ns->next;

} while(ns);
}

return [self _recursiveResolveNamespaceForPrefix:prefix atNode:nodePtr->parent];
Expand Down Expand Up @@ -635,16 +663,21 @@ - (NSString *)_recursiveResolvePrefixForURI:(NSString *)uri atNode:(xmlNodePtr)n
if (nodePtr == NULL) return nil;

xmlNsPtr ns = nodePtr->nsDef;
while (ns != NULL)
if (ns)
{
if (xmlStrEqual(ns->href, [uri xmlChar]))
const xmlChar *xmlUri = [uri xmlChar];
do
{
if (ns->prefix != NULL)
if (xmlStrEqual(ns->href, xmlUri))
{
return [NSString stringWithUTF8String:((const char *)ns->prefix)];
if (ns->prefix != NULL)
{
return [NSString stringWithUTF8String:((const char *)ns->prefix)];
}
}
}
ns = ns->next;
ns = ns->next;

} while (ns);
}

return [self _recursiveResolvePrefixForURI:uri atNode:nodePtr->parent];
Expand Down

0 comments on commit b2f387f

Please sign in to comment.