diff --git a/ChangeLog b/ChangeLog index 585cbbebf..d4a8f98df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-01-26 22:28-CET Niels Grewe + + * Source/NSXMLElement.m: Fix behaviour of -addAttribute:. Implement + -attributeForName: + * Tests/base/NSXMLElement/attributes.m: Add some attribute tests. + 2012-01-24 21:59-EST Gregory John Casamento * Tests/base/NSXMLElement/children.m: Remove test based diff --git a/Source/NSXMLElement.m b/Source/NSXMLElement.m index 0a96e5250..a5f0bc5c2 100644 --- a/Source/NSXMLElement.m +++ b/Source/NSXMLElement.m @@ -10,7 +10,7 @@ modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU @@ -136,10 +136,38 @@ extern void clearPrivatePointers(xmlNodePtr aNode); { xmlNodePtr node = (xmlNodePtr)(internal->node); xmlAttrPtr attr = (xmlAttrPtr)[attribute _node]; - //xmlAddChild(node,attr); -// xmlSetProp(node, attr->name, attr->children); - xmlAttrPtr newAttr = xmlCopyProp(node, attr); - [attribute _setNode:newAttr]; + xmlAttrPtr oldAttr = xmlHasProp(node, attr->name); + if (nil != [attribute parent]) + { + [NSException raise: @"NSInvalidArgumentException" + format: @"Tried to add attribute to multiple parents."]; + } + + if (NULL != oldAttr) + { + /* + * As per Cocoa documentation, we only add the attribute if it's not + * already set. xmlHasProp() also looks at the DTD for default attributes + * and we need to make sure that we only bail out here on #FIXED + * attributes. + */ + + // Do not replace plain attributes. + if (XML_ATTRIBUTE_NODE == oldAttr->type) + { + return; + } + else if (XML_ATTRIBUTE_DECL == oldAttr->type) + { + // If the attribute is from a DTD, do not replace it if it's #FIXED + xmlAttributePtr attrDecl = (xmlAttributePtr)oldAttr; + if (XML_ATTRIBUTE_FIXED == attrDecl->def) + { + return; + } + } + } + xmlAddChild(node, (xmlNodePtr)attr); [self _addSubNode:attribute]; } @@ -167,16 +195,16 @@ extern void clearPrivatePointers(xmlNodePtr aNode); - (void) setAttributesWithDictionary: (NSDictionary*)attributes { - NSEnumerator *en = [attributes keyEnumerator]; - NSString *key; - + NSEnumerator *en = [attributes keyEnumerator]; + NSString *key; + // [internal->attributes removeAllObjects]; - while ((key = [en nextObject]) != nil) - { - NSString *val = [[attributes objectForKey: key] stringValue]; - NSXMLNode *attribute = [NSXMLNode attributeWithName: key + while ((key = [en nextObject]) != nil) + { + NSString *val = [[attributes objectForKey: key] stringValue]; + NSXMLNode *attribute = [NSXMLNode attributeWithName: key stringValue: val]; - [self addAttribute: attribute]; + [self addAttribute: attribute]; } } @@ -196,8 +224,16 @@ extern void clearPrivatePointers(xmlNodePtr aNode); - (NSXMLNode*) attributeForName: (NSString*)name { - [self notImplemented: _cmd]; - return nil; // [internal->attributes objectForKey: name]; + NSXMLNode *result = nil; + xmlChar *xmlName = xmlCharStrdup([name UTF8String]); + xmlAttrPtr attributeNode = xmlHasProp(MY_NODE, xmlName); + if (NULL != attributeNode) + { + result = [NSXMLNode _objectForNode:(xmlNodePtr)attributeNode]; + } + xmlFree(xmlName); + xmlName = NULL; + return result; // [internal->attributes objectForKey: name]; } - (NSXMLNode*) attributeForLocalName: (NSString*)localName @@ -253,7 +289,7 @@ extern void clearPrivatePointers(xmlNodePtr aNode); [result addObject: StringFromXMLStringPtr(cur->prefix)]; } } - + // [self notImplemented: _cmd]; return result; // nil; // internal->namespaces; } @@ -311,7 +347,7 @@ extern void clearPrivatePointers(xmlNodePtr aNode); { xmlAddNextSibling(curNode, childNode); } - + [self _addSubNode:child]; } @@ -319,7 +355,7 @@ extern void clearPrivatePointers(xmlNodePtr aNode); { NSEnumerator *enumerator = [children objectEnumerator]; NSXMLNode *child; - + while ((child = [enumerator nextObject]) != nil) { [self insertChild: child atIndex: index++]; @@ -346,7 +382,7 @@ extern void clearPrivatePointers(xmlNodePtr aNode); { NSEnumerator *en; NSXMLNode *child; - + while ([self childCount] > 0) { [self removeChildAtIndex: [self childCount] - 1]; @@ -357,13 +393,13 @@ extern void clearPrivatePointers(xmlNodePtr aNode); [self insertChild: child atIndex: [self childCount]]; } } - + - (void) addChild: (NSXMLNode*)child { int count = [self childCount]; [self insertChild: child atIndex: count]; } - + - (void) replaceChildAtIndex: (NSUInteger)index withNode: (NSXMLNode*)node { [self insertChild: node atIndex: index]; @@ -404,7 +440,7 @@ extern void clearPrivatePointers(xmlNodePtr aNode); [c addAttribute: attr]; [attr release]; } - + en = [[self children] objectEnumerator]; while ((obj = [en nextObject]) != nil) { diff --git a/Tests/base/NSXMLElement/attributes.m b/Tests/base/NSXMLElement/attributes.m new file mode 100644 index 000000000..af6cdb39e --- /dev/null +++ b/Tests/base/NSXMLElement/attributes.m @@ -0,0 +1,49 @@ +#import "ObjectTesting.h" +#import +#import +#import + +int main() +{ + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSXMLElement *root1; + NSXMLElement *root2; + NSXMLNode *attr1; + NSXMLNode *attr2; + NSXMLNode *attrSameNameAsAttr1; + + root1 = [[NSXMLElement alloc] initWithName: @"root1"]; + root2 = [[NSXMLElement alloc] initWithName: @"root2"]; + + attr1 = [NSXMLNode attributeWithName: @"attr1" stringValue: @"foo"]; + attr2 = [NSXMLNode attributeWithName: @"attr2" stringValue: @"foo"]; + attrSameNameAsAttr1 = [NSXMLNode attributeWithName: @"attr1" stringValue: @"foo"]; + + + PASS_RUNS([root1 addAttribute: attr1], + "may add attributes"); + [root1 addAttribute: attr2]; + PASS_EQUAL([root1 attributeForName: @"attr1"], attr1, + "element returns attribute by name"); + PASS_RUNS([root1 removeAttributeForName: @"attr2"], + "removing attributes by name works"); + PASS_EQUAL([root1 attributeForName: @"attr2"], nil, + "attribute is nil after removal"); + + [root1 addAttribute: attrSameNameAsAttr1]; + PASS_EQUAL([root1 attributeForName: @"attr1"], attr1, + "may not overwrite pre-existing attributes"); + + PASS_EXCEPTION([root2 addAttribute: attr1], + NSInvalidArgumentException, + "cannot add attributes to multiple parents"); + + + + [root1 release]; + [root2 release]; + [arp release]; + arp = nil; + + return 0; +}