@@ -23,10 +23,12 @@ #import "OFString.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFDataArray.h" #import "OFXMLAttribute.h" +#import "OFXMLCharacters.h" +#import "OFXMLCDATA.h" #import "OFXMLParser.h" #import "OFXMLElementBuilder.h" #import "OFAutoreleasePool.h" #import "OFInvalidArgumentException.h" @@ -40,10 +42,13 @@ /* References for static linking */ void _references_to_categories_of_OFXMLElement(void) { _OFXMLElement_Serialization_reference = 1; } + +static Class charactersClass = Nil; +static Class CDATAClass = Nil; @interface OFXMLElement_OFXMLElementBuilderDelegate: OFObject { @public OFXMLElement *element; @@ -52,18 +57,12 @@ @implementation OFXMLElement_OFXMLElementBuilderDelegate - (void)elementBuilder: (OFXMLElementBuilder*)builder didBuildElement: (OFXMLElement*)element_ { - /* - * Make sure we don't take whitespaces before or after the root element - * into account. - */ - if ([element_ name] != nil) { - assert(element == nil); + if (element == nil) element = [element_ retain]; - } } - (void)dealloc { [element release]; @@ -71,10 +70,18 @@ [super dealloc]; } @end @implementation OFXMLElement ++ (void)initialize +{ + if (self == [OFXMLElement class]) { + charactersClass = [OFXMLCharacters class]; + CDATAClass = [OFXMLCDATA class]; + } +} + + elementWithName: (OFString*)name { return [[[self alloc] initWithName: name] autorelease]; } @@ -99,25 +106,10 @@ return [[[self alloc] initWithName: name namespace: ns stringValue: stringValue] autorelease]; } -+ elementWithCharacters: (OFString*)characters -{ - return [[[self alloc] initWithCharacters: characters] autorelease]; -} - -+ elementWithCDATA: (OFString*)CDATA -{ - return [[[self alloc] initWithCDATA: CDATA] autorelease]; -} - -+ elementWithComment: (OFString*)comment -{ - return [[[self alloc] initWithComment: comment] autorelease]; -} - + elementWithElement: (OFXMLElement*)element { return [[[self alloc] initWithElement: element] autorelease]; } @@ -190,67 +182,10 @@ } return self; } -- initWithCharacters: (OFString*)characters_ -{ - self = [super init]; - - @try { - if (characters_ == nil) - @throw [OFInvalidArgumentException - exceptionWithClass: isa - selector: _cmd]; - - characters = [characters_ copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- initWithCDATA: (OFString*)CDATA_ -{ - self = [super init]; - - @try { - if (CDATA_ == nil) - @throw [OFInvalidArgumentException - exceptionWithClass: isa - selector: _cmd]; - - CDATA = [CDATA_ copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- initWithComment: (OFString*)comment_ -{ - self = [super init]; - - @try { - if (comment_ == nil) - @throw [OFInvalidArgumentException - exceptionWithClass: isa - selector: _cmd]; - - comment = [comment_ copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - - initWithElement: (OFXMLElement*)element { self = [super init]; @try { @@ -263,13 +198,10 @@ ns = [element->ns copy]; defaultNamespace = [element->defaultNamespace copy]; attributes = [element->attributes mutableCopy]; namespaces = [element->namespaces mutableCopy]; children = [element->children mutableCopy]; - characters = [element->characters copy]; - CDATA = [element->CDATA copy]; - comment = [element->comment copy]; } @catch (id e) { [self release]; @throw e; } @@ -366,19 +298,10 @@ name = [[[element attributeForName: @"name"] stringValue] copy]; ns = [[[element attributeForName: @"namespace"] stringValue] copy]; defaultNamespace = [[[element attributeForName: @"defaultNamespace"] stringValue] copy]; - characters = [[[element - elementForName: @"characters" - namespace: OF_SERIALIZATION_NS] stringValue] copy]; - CDATA = [[[element - elementForName: @"CDATA" - namespace: OF_SERIALIZATION_NS] stringValue] copy]; - comment = [[[element - elementForName: @"comment" - namespace: OF_SERIALIZATION_NS] stringValue] copy]; attributesElement = [[[element elementForName: @"attributes" namespace: OF_SERIALIZATION_NS] elementsForNamespace: OF_SERIALIZATION_NS] firstObject]; @@ -393,14 +316,11 @@ attributes = [[attributesElement objectByDeserializing] copy]; namespaces = [[namespacesElement objectByDeserializing] copy]; children = [[childrenElement objectByDeserializing] copy]; - if (!((name != nil || ns != nil || defaultNamespace != nil || - [attributes count] > 0 || [namespaces count] > 0 || - [children count] > 0) ^ (characters != nil) ^ - (CDATA != nil) ^ (comment != nil))) + if (name == nil) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; [pool release]; @@ -412,11 +332,11 @@ return self; } - (void)setName: (OFString*)name_ { - if (name == nil) + if (name_ == nil) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; OF_SETTER(name, name_, YES, YES) } @@ -426,14 +346,10 @@ return [[name copy] autorelease]; } - (void)setNamespace: (OFString*)ns_ { - if (name == nil) - @throw [OFInvalidArgumentException exceptionWithClass: isa - selector: _cmd]; - OF_SETTER(ns, ns_, YES, YES) } - (OFString*)namespace { @@ -460,11 +376,11 @@ - (void)setStringValue: (OFString*)stringValue { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; [self setChildren: [OFArray arrayWithObject: - [OFXMLElement elementWithCharacters: stringValue]]]; + [OFXMLCharacters charactersWithString: stringValue]]]; [pool release]; } - (OFString*)stringValue @@ -480,18 +396,12 @@ ret = [OFMutableString string]; cArray = [children cArray]; pool = [[OFAutoreleasePool alloc] init]; for (i = 0; i < count; i++) { - if (cArray[i]->characters != nil) - [ret appendString: cArray[i]->characters]; - else if (cArray[i]->CDATA != nil) - [ret appendString: cArray[i]->CDATA]; - else if (cArray[i]->comment == nil) { - [ret appendString: [cArray[i] stringValue]]; - [pool releaseObjects]; - } + [ret appendString: [cArray[i] stringValue]]; + [pool releaseObjects]; } [ret makeImmutable]; [pool release]; @@ -500,47 +410,20 @@ } - (OFString*)_XMLStringWithParent: (OFXMLElement*)parent namespaces: (OFDictionary*)allNamespaces indentation: (unsigned int)indentation - level: (size_t)level + level: (unsigned int)level { OFAutoreleasePool *pool, *pool2; char *cString; size_t length, i, j, attributesCount; OFString *prefix, *parentPrefix; OFXMLAttribute **attributesCArray; OFString *ret; OFString *defaultNS; - if (characters != nil) - return [characters stringByXMLEscaping]; - - if (CDATA != nil) - return [OFString stringWithFormat: @"", CDATA]; - - if (comment != nil) { - if (indentation > 0 && level > 0) { - char *whitespaces = [self - allocMemoryWithSize: (level * indentation) + 1]; - memset(whitespaces, ' ', level * indentation); - whitespaces[level * indentation] = 0; - - @try { - ret = [OFString - stringWithFormat: @"%s", - whitespaces, comment]; - } @finally { - [self freeMemory: whitespaces]; - } - } else - ret = [OFString stringWithFormat: @"", - comment]; - - return ret; - } - pool = [[OFAutoreleasePool alloc] init]; parentPrefix = [allNamespaces objectForKey: (parent != nil && parent->ns != nil ? parent->ns : (OFString*)@"")]; @@ -680,30 +563,37 @@ if (indentation > 0) { indent = YES; for (j = 0; j < childrenCount; j++) { - if (childrenCArray[j]->characters != nil || - childrenCArray[j]->CDATA != nil) { + if (childrenCArray[j]->isa == charactersClass || + childrenCArray[j]->isa == CDATAClass) { indent = NO; break; } } } else indent = NO; for (j = 0; j < childrenCount; j++) { OFString *child; + unsigned int ind = (indent ? indentation : 0); - if (indent) + if (ind) [tmp addItem: "\n"]; - child = [childrenCArray[j] - _XMLStringWithParent: self - namespaces: allNamespaces - indentation: (indent ? indentation : 0) - level: level + 1]; + if ([childrenCArray[j] isKindOfClass: + [OFXMLElement class]]) + child = [childrenCArray[j] + _XMLStringWithParent: self + namespaces: allNamespaces + indentation: ind + level: level + 1]; + else + child = [childrenCArray[j] + XMLStringWithIndentation: ind + level: level + 1]; [tmp addNItems: [child UTF8StringLength] fromCArray: [child UTF8String]]; } @@ -779,10 +669,19 @@ return [self _XMLStringWithParent: nil namespaces: nil indentation: indentation level: 0]; } + +- (OFString*)XMLStringWithIndentation: (unsigned int)indentation + level: (unsigned int)level +{ + return [self _XMLStringWithParent: nil + namespaces: nil + indentation: indentation + level: level]; +} - (OFXMLElement*)XMLElementBySerializing { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFXMLElement *element; @@ -832,43 +731,19 @@ namespace: OF_SERIALIZATION_NS]; [childrenElement addChild: [children XMLElementBySerializing]]; [element addChild: childrenElement]; } - if (characters != nil) - [element addChild: - [OFXMLElement elementWithName: @"characters" - namespace: OF_SERIALIZATION_NS - stringValue: characters]]; - - if (CDATA != nil) { - OFXMLElement *CDATAElement = - [OFXMLElement elementWithName: @"CDATA" - namespace: OF_SERIALIZATION_NS]; - [CDATAElement addChild: [OFXMLElement elementWithCDATA: CDATA]]; - [element addChild: CDATAElement]; - } - - if (comment != nil) - [element addChild: - [OFXMLElement elementWithName: @"comment" - namespace: OF_SERIALIZATION_NS - stringValue: comment]]; - [element retain]; [pool release]; [element autorelease]; return element; } - (void)addAttribute: (OFXMLAttribute*)attribute { - if (name == nil) - @throw [OFInvalidArgumentException exceptionWithClass: isa - selector: _cmd]; - if (attributes == nil) attributes = [[OFMutableArray alloc] init]; if ([self attributeForName: attribute->name namespace: attribute->ns] == nil) @@ -885,20 +760,16 @@ - (void)addAttributeWithName: (OFString*)name_ namespace: (OFString*)ns_ stringValue: (OFString*)stringValue { - OFAutoreleasePool *pool; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - if (name == nil) - @throw [OFInvalidArgumentException exceptionWithClass: isa - selector: _cmd]; - - pool = [[OFAutoreleasePool alloc] init]; [self addAttribute: [OFXMLAttribute attributeWithName: name_ namespace: ns_ stringValue: stringValue]]; + [pool release]; } - (OFXMLAttribute*)attributeForName: (OFString*)attributeName { @@ -970,11 +841,11 @@ } - (void)setPrefix: (OFString*)prefix forNamespace: (OFString*)ns_ { - if (name == nil || prefix == nil || [prefix isEqual: @""]) + if (prefix == nil || [prefix isEqual: @""]) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; if (ns_ == nil) ns_ = @""; @@ -992,43 +863,33 @@ stringValue: ns_]; } - (OFString*)defaultNamespace { - if (name == nil) - @throw [OFInvalidArgumentException exceptionWithClass: isa - selector: _cmd]; - - return [[defaultNamespace retain] autorelease]; + OF_GETTER(defaultNamespace, YES) } - (void)setDefaultNamespace: (OFString*)ns_ { - if (name == nil) - @throw [OFInvalidArgumentException exceptionWithClass: isa - selector: _cmd]; - - OFString *old = defaultNamespace; - defaultNamespace = [ns_ copy]; - [old release]; + OF_SETTER(defaultNamespace, ns_, YES, YES) } -- (void)addChild: (OFXMLElement*)child +- (void)addChild: (OFXMLNode*)child { - if (name == nil) + if ([child isKindOfClass: [OFXMLAttribute class]]) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; if (children == nil) children = [[OFMutableArray alloc] init]; [children addObject: child]; } -- (void)removeChild: (OFXMLElement*)child +- (void)removeChild: (OFXMLNode*)child { - if (name == nil) + if ([child isKindOfClass: [OFXMLAttribute class]]) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; [children removeObject: child]; } @@ -1050,11 +911,11 @@ OFMutableArray *ret = [OFMutableArray array]; OFXMLElement **cArray = [children cArray]; size_t i, count = [children count]; for (i = 0; i < count; i++) - if (cArray[i]->name != nil) + if ([cArray[i] isKindOfClass: [OFXMLElement class]]) [ret addObject: cArray[i]]; [ret makeImmutable]; return ret; @@ -1065,11 +926,12 @@ OFMutableArray *ret = [OFMutableArray array]; OFXMLElement **cArray = [children cArray]; size_t i, count = [children count]; for (i = 0; i < count; i++) - if (cArray[i]->ns == nil && + if ([cArray[i] isKindOfClass: [OFXMLElement class]] && + cArray[i]->ns == nil && [cArray[i]->name isEqual: elementName]) [ret addObject: cArray[i]]; [ret makeImmutable]; @@ -1081,11 +943,12 @@ OFMutableArray *ret = [OFMutableArray array]; OFXMLElement **cArray = [children cArray]; size_t i, count = [children count]; for (i = 0; i < count; i++) - if (cArray[i]->name != nil && + if ([cArray[i] isKindOfClass: [OFXMLElement class]] && + cArray[i]->name != nil && [cArray[i]->ns isEqual: elementNS]) [ret addObject: cArray[i]]; [ret makeImmutable]; @@ -1105,11 +968,12 @@ ret = [OFMutableArray array]; cArray = [children cArray]; count = [children count]; for (i = 0; i < count; i++) - if ([cArray[i]->ns isEqual: elementNS] && + if ([cArray[i] isKindOfClass: [OFXMLElement class]] && + [cArray[i]->ns isEqual: elementNS] && [cArray[i]->name isEqual: elementName]) [ret addObject: cArray[i]]; [ret makeImmutable]; @@ -1139,19 +1003,10 @@ ![otherElement->namespaces isEqual: namespaces]) return NO; if (otherElement->children != children && ![otherElement->children isEqual: children]) return NO; - if (otherElement->characters != characters && - ![otherElement->characters isEqual: characters]) - return NO; - if (otherElement->CDATA != CDATA && - ![otherElement->CDATA isEqual: CDATA]) - return NO; - if (otherElement->comment != comment && - ![otherElement->comment isEqual: comment]) - return NO; return YES; } - (uint32_t)hash @@ -1164,13 +1019,10 @@ OF_HASH_ADD_HASH(hash, [ns hash]); OF_HASH_ADD_HASH(hash, [defaultNamespace hash]); OF_HASH_ADD_HASH(hash, [attributes hash]); OF_HASH_ADD_HASH(hash, [namespaces hash]); OF_HASH_ADD_HASH(hash, [children hash]); - OF_HASH_ADD_HASH(hash, [characters hash]); - OF_HASH_ADD_HASH(hash, [CDATA hash]); - OF_HASH_ADD_HASH(hash, [comment hash]); OF_HASH_FINALIZE(hash); return hash; } @@ -1186,12 +1038,9 @@ [ns release]; [defaultNamespace release]; [attributes release]; [namespaces release]; [children release]; - [characters release]; - [CDATA release]; - [comment release]; [super dealloc]; } @end