diff --git a/GDataXML-HTML/lib/GDataXMLNode.h b/GDataXML-HTML/lib/GDataXMLNode.h index e757630..4ea554d 100644 --- a/GDataXML-HTML/lib/GDataXMLNode.h +++ b/GDataXML-HTML/lib/GDataXMLNode.h @@ -139,6 +139,10 @@ typedef NSUInteger GDataXMLNodeKind; - (NSArray *)children; - (GDataXMLNode *)childAtIndex:(unsigned)index; +- (GDataXMLNode *)parent; + +- (NSUInteger)index; + - (NSString *)localName; - (NSString *)name; - (NSString *)prefix; @@ -185,6 +189,7 @@ typedef NSUInteger GDataXMLNodeKind; // addChild adds a copy of the child node to the element - (void)addChild:(GDataXMLNode *)child; - (void)removeChild:(GDataXMLNode *)child; +- (void)removeChildAtIndex:(NSUInteger)index; - (NSArray *)elementsForName:(NSString *)name; - (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI; @@ -193,6 +198,7 @@ typedef NSUInteger GDataXMLNodeKind; - (GDataXMLNode *)attributeForName:(NSString *)name; - (GDataXMLNode *)attributeForLocalName:(NSString *)name URI:(NSString *)attributeURI; - (void)addAttribute:(GDataXMLNode *)attribute; +- (void)removeAttributeForName:(NSString *)name; - (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI; diff --git a/GDataXML-HTML/lib/GDataXMLNode.m b/GDataXML-HTML/lib/GDataXMLNode.m index 737a8da..3939f7c 100644 --- a/GDataXML-HTML/lib/GDataXMLNode.m +++ b/GDataXML-HTML/lib/GDataXMLNode.m @@ -375,6 +375,68 @@ - (NSString *)stringFromXMLString:(const xmlChar *)chars { return result; } +/** + * Removes and free's the given attribute from its parent node. + * The attribute's surrounding prev/next pointers are properly updated to remove the attribute from the attr list. + **/ ++ (void)removeAttribute:(xmlAttrPtr)attr +{ + // We perform a bit of optimization here. + // No need to bother nullifying pointers since we're about to free the node anyway. + [self detachAttribute:attr andClean:NO]; + + xmlFreeProp(attr); +} + +/** + * Detaches the given attribute from its parent node. + * The attribute's surrounding prev/next pointers are properly updated to remove the attribute from the attr list. + * Then, if the clean flag is YES, the attribute's parent, prev, next and doc pointers are set to null. + **/ ++ (void)detachAttribute:(xmlAttrPtr)attr andClean:(BOOL)clean +{ + xmlNodePtr parent = attr->parent; + + // Update the surrounding prev/next pointers + if (attr->prev == NULL) + { + parent->properties = attr->next; + if (attr->next != NULL) { + attr->next->prev = NULL; + } + } + else + { + attr->prev->next = attr->next; + if (attr->next != NULL) { + attr->next->prev = attr->prev; + } + } + + if (clean) + { + // Nullify pointers + attr->parent = NULL; + attr->prev = NULL; + attr->next = NULL; + attr->ns = NULL; + if (attr->doc != NULL) [self stripDocPointersFromAttr:attr]; + } +} + ++ (void)stripDocPointersFromAttr:(xmlAttrPtr)attr +{ + xmlNodePtr child = attr->children; + while (child != NULL) + { + child->doc = NULL; + child = child->next; + } + + attr->doc = NULL; +} + + - (void)dealloc { if (xmlNode_ && shouldFreeXMLNode_) { @@ -652,6 +714,27 @@ - (GDataXMLNode *)childAtIndex:(unsigned)index { return nil; } +- (GDataXMLNode *)parent { + xmlNodePtr node = xmlNode_; + + if (node->parent == NULL) + return nil; + else + return [GDataXMLNode nodeBorrowingXMLNode:node->parent]; +} + +- (NSUInteger)index { + NSUInteger result = 0; + xmlNodePtr node = xmlNode_->prev; + while (node != NULL) + { + result++; + node = node->prev; + } + + return result; +} + - (GDataXMLNodeKind)kind { if (xmlNode_ != NULL) { xmlElementType nodeType = xmlNode_->type; @@ -1115,6 +1198,11 @@ - (void)removeChild:(GDataXMLNode *)child { } } +- (void)removeChildAtIndex:(NSUInteger)index +{ + [self removeChild:[self childAtIndex:index]]; +} + - (NSArray *)elementsForName:(NSString *)name { NSString *desiredName = name; @@ -1326,6 +1414,26 @@ - (void)addAttribute:(GDataXMLNode *)attribute { } } +- (void)removeAttributeForName:(NSString *)name { + // This is a private/internal method + + xmlAttrPtr attr = (xmlNode_)->properties; + if (attr) + { + const xmlChar *xmlName = (const xmlChar *)[name UTF8String];; + do + { + if (xmlStrEqual(attr->name, xmlName)) + { + [GDataXMLNode removeAttribute:attr]; + return; + } + attr = attr->next; + + } while(attr); + } +} + - (GDataXMLNode *)attributeForXMLNode:(xmlAttrPtr)theXMLNode { // search the cached attributes list for the GDataXMLNode with // the underlying xmlAttrPtr @@ -1981,4 +2089,3 @@ static CFHashCode StringCacheKeyHashCallBack(const void *str) { } return hash; } -