@@ -71,11 +71,10 @@ } @end @implementation OFXMLElement @synthesize name = _name, namespace = _namespace; -@synthesize defaultNamespace = _defaultNamespace; + (instancetype)elementWithName: (OFString *)name { return [[[self alloc] initWithName: name] autorelease]; } @@ -101,15 +100,10 @@ return [[[self alloc] initWithName: name namespace: namespace stringValue: stringValue] autorelease]; } -+ (instancetype)elementWithElement: (OFXMLElement *)element -{ - return [[[self alloc] initWithElement: element] autorelease]; -} - + (instancetype)elementWithXMLString: (OFString *)string { return [[[self alloc] initWithXMLString: string] autorelease]; } @@ -137,17 +131,10 @@ } - (instancetype)initWithName: (OFString *)name namespace: (OFString *)namespace { - return [self initWithName: name namespace: namespace stringValue: nil]; -} - -- (instancetype)initWithName: (OFString *)name - namespace: (OFString *)namespace - stringValue: (OFString *)stringValue -{ self = [super of_init]; @try { if (name == nil) @throw [OFInvalidArgumentException exception]; @@ -157,36 +144,27 @@ _namespaces = [[OFMutableDictionary alloc] initWithKeysAndObjects: @"http://www.w3.org/XML/1998/namespace", @"xml", @"http://www.w3.org/2000/xmlns/", @"xmlns", nil]; - - if (stringValue != nil) - self.stringValue = stringValue; } @catch (id e) { [self release]; @throw e; } return self; } -- (instancetype)initWithElement: (OFXMLElement *)element +- (instancetype)initWithName: (OFString *)name + namespace: (OFString *)namespace + stringValue: (OFString *)stringValue { - self = [super of_init]; + self = [self initWithName: name namespace: namespace]; @try { - if (element == nil || - ![element isKindOfClass: [OFXMLElement class]]) - @throw [OFInvalidArgumentException exception]; - - _name = [element->_name copy]; - _namespace = [element->_namespace copy]; - _defaultNamespace = [element->_defaultNamespace copy]; - _attributes = [element->_attributes mutableCopy]; - _namespaces = [element->_namespaces mutableCopy]; - _children = [element->_children mutableCopy]; + if (stringValue != nil) + self.stringValue = stringValue; } @catch (id e) { [self release]; @throw e; } @@ -194,110 +172,167 @@ } - (instancetype)initWithXMLString: (OFString *)string { void *pool; - OFXMLParser *parser; - OFXMLElementBuilder *builder; - OFXMLElementElementBuilderDelegate *delegate; - - [self release]; - - if (string == nil) - @throw [OFInvalidArgumentException exception]; - - pool = objc_autoreleasePoolPush(); - - parser = [OFXMLParser parser]; - builder = [OFXMLElementBuilder builder]; - delegate = [[[OFXMLElementElementBuilderDelegate alloc] init] - autorelease]; - - parser.delegate = builder; - builder.delegate = delegate; - - [parser parseString: string]; - - if (!parser.hasFinishedParsing) - @throw [OFMalformedXMLException exceptionWithParser: parser]; - - self = [delegate->_element retain]; - - objc_autoreleasePoolPop(pool); + OFXMLElement *element; + + @try { + OFXMLParser *parser; + OFXMLElementBuilder *builder; + OFXMLElementElementBuilderDelegate *delegate; + + if (string == nil) + @throw [OFInvalidArgumentException exception]; + + pool = objc_autoreleasePoolPush(); + + parser = [OFXMLParser parser]; + builder = [OFXMLElementBuilder builder]; + delegate = [[[OFXMLElementElementBuilderDelegate alloc] init] + autorelease]; + + parser.delegate = builder; + builder.delegate = delegate; + + [parser parseString: string]; + + if (!parser.hasFinishedParsing) + @throw [OFMalformedXMLException + exceptionWithParser: parser]; + + element = delegate->_element; + } @catch (id e) { + [self release]; + @throw e; + } + + self = [self initWithName: element->_name + namespace: element->_namespace]; + + @try { + [_attributes release]; + _attributes = [element->_attributes retain]; + [_namespaces release]; + _namespaces = [element->_namespaces retain]; + [_children release]; + _children = [element->_children retain]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } return self; } - (instancetype)initWithStream: (OFStream *)stream { void *pool; - OFXMLParser *parser; - OFXMLElementBuilder *builder; - OFXMLElementElementBuilderDelegate *delegate; - - [self release]; - - pool = objc_autoreleasePoolPush(); - - parser = [OFXMLParser parser]; - builder = [OFXMLElementBuilder builder]; - delegate = [[[OFXMLElementElementBuilderDelegate alloc] init] - autorelease]; - - parser.delegate = builder; - builder.delegate = delegate; - - [parser parseStream: stream]; - - if (!parser.hasFinishedParsing) - @throw [OFMalformedXMLException exceptionWithParser: parser]; - - self = [delegate->_element retain]; - - objc_autoreleasePoolPop(pool); + OFXMLElement *element; + + @try { + OFXMLParser *parser; + OFXMLElementBuilder *builder; + OFXMLElementElementBuilderDelegate *delegate; + + pool = objc_autoreleasePoolPush(); + + parser = [OFXMLParser parser]; + builder = [OFXMLElementBuilder builder]; + delegate = [[[OFXMLElementElementBuilderDelegate alloc] init] + autorelease]; + + parser.delegate = builder; + builder.delegate = delegate; + + [parser parseStream: stream]; + + if (!parser.hasFinishedParsing) + @throw [OFMalformedXMLException + exceptionWithParser: parser]; + + element = delegate->_element; + } @catch (id e) { + [self release]; + @throw e; + } + + self = [self initWithName: element->_name + namespace: element->_namespace]; + + @try { + [_attributes release]; + _attributes = [element->_attributes retain]; + [_namespaces release]; + _namespaces = [element->_namespaces retain]; + [_children release]; + _children = [element->_children retain]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } return self; } - (instancetype)initWithSerialization: (OFXMLElement *)element { - self = [super of_init]; + void *pool; + OFString *name, *namespace; @try { - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *attributesElement, *namespacesElement; - OFXMLElement *childrenElement; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFString *key, *object; + pool = objc_autoreleasePoolPush(); if (![element.name isEqual: self.className] || ![element.namespace isEqual: OFSerializationNS]) @throw [OFInvalidArgumentException exception]; - _name = [[element attributeForName: @"name"].stringValue copy]; - _namespace = [[element attributeForName: @"namespace"] - .stringValue copy]; - _defaultNamespace = [[element attributeForName: - @"defaultNamespace"].stringValue copy]; + name = [element attributeForName: @"name"].stringValue; + namespace = + [element attributeForName: @"namespace"].stringValue; + } @catch (id e) { + [self release]; + @throw e; + } + + self = [self initWithName: name namespace: namespace]; + + @try { + OFXMLElement *attributesElement, *namespacesElement; + OFXMLElement *childrenElement; + OFEnumerator *keyEnumerator, *objectEnumerator; + OFString *key, *object; attributesElement = [[element elementForName: @"attributes" - namespace: OFSerializationNS] elementsForNamespace: - OFSerializationNS].firstObject; + namespace: OFSerializationNS] + elementsForNamespace: OFSerializationNS].firstObject; namespacesElement = [[element elementForName: @"namespaces" - namespace: OFSerializationNS] elementsForNamespace: - OFSerializationNS].firstObject; + namespace: OFSerializationNS] + elementsForNamespace: OFSerializationNS].firstObject; childrenElement = [[element elementForName: @"children" - namespace: OFSerializationNS] elementsForNamespace: - OFSerializationNS].firstObject; + namespace: OFSerializationNS] + elementsForNamespace: OFSerializationNS].firstObject; + [_attributes release]; + _attributes = nil; _attributes = [attributesElement.objectByDeserializing mutableCopy]; + + [_namespaces release]; + _namespaces = nil; _namespaces = [namespacesElement.objectByDeserializing mutableCopy]; + + [_children release]; + _children = nil; _children = [childrenElement.objectByDeserializing mutableCopy]; /* Sanity checks */ if ((_attributes != nil && ![_attributes isKindOfClass: @@ -330,13 +365,10 @@ setObject: @"xml" forKey: @"http://www.w3.org/XML/1998/namespace"]; [_namespaces setObject: @"xmlns" forKey: @"http://www.w3.org/2000/xmlns/"]; - if (_name == nil) - @throw [OFInvalidArgumentException exception]; - objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } @@ -346,11 +378,10 @@ - (void)dealloc { [_name release]; [_namespace release]; - [_defaultNamespace release]; [_attributes release]; [_namespaces release]; [_children release]; [super dealloc]; @@ -403,28 +434,22 @@ [ret makeImmutable]; return ret; } -- (OFString *)of_XMLStringWithParent: (OFXMLElement *)parent - namespaces: (OFDictionary *)allNS - indentation: (unsigned int)indentation - level: (unsigned int)level OF_DIRECT +- (OFString *)of_XMLStringWithDefaultNS: (OFString *)defaultNS + namespaces: (OFDictionary *)allNS + indentation: (unsigned int)indentation + level: (unsigned int)level OF_DIRECT { void *pool; char *cString; size_t length, i; - OFString *prefix, *parentPrefix; - OFString *ret; - OFString *defaultNS; + OFString *prefix, *ret; pool = objc_autoreleasePoolPush(); - parentPrefix = [allNS objectForKey: - (parent != nil && parent->_namespace != nil - ? parent->_namespace : (OFString *)@"")]; - /* Add the namespaces of the current element */ if (allNS != nil) { OFEnumerator *keyEnumerator = [_namespaces keyEnumerator]; OFEnumerator *objectEnumerator = [_namespaces objectEnumerator]; OFMutableDictionary *tmp; @@ -441,17 +466,10 @@ allNS = _namespaces; prefix = [allNS objectForKey: (_namespace != nil ? _namespace : (OFString *)@"")]; - if (parent != nil && parent->_namespace != nil && parentPrefix == nil) - defaultNS = parent->_namespace; - else if (parent != nil && parent->_defaultNamespace != nil) - defaultNS = parent->_defaultNamespace; - else - defaultNS = _defaultNamespace; - i = 0; length = _name.UTF8StringLength + 3 + (level * indentation); cString = OFAllocMemory(length, 1); @try { @@ -459,11 +477,11 @@ i += level * indentation; /* Start of tag */ cString[i++] = '<'; - if (prefix != nil && ![_namespace isEqual: defaultNS]) { + if (prefix.length > 0) { length += prefix.UTF8StringLength + 1; cString = OFResizeMemory(cString, length, 1); memcpy(cString + i, prefix.UTF8String, prefix.UTF8StringLength); @@ -473,22 +491,23 @@ memcpy(cString + i, _name.UTF8String, _name.UTF8StringLength); i += _name.UTF8StringLength; /* xmlns if necessary */ - if (prefix == nil && ((_namespace != nil && - ![_namespace isEqual: defaultNS]) || - (_namespace == nil && defaultNS != nil))) { + if (prefix.length == 0 && defaultNS != _namespace && + ![defaultNS isEqual: _namespace]) { length += _namespace.UTF8StringLength + 9; cString = OFResizeMemory(cString, length, 1); memcpy(cString + i, " xmlns='", 8); i += 8; memcpy(cString + i, _namespace.UTF8String, _namespace.UTF8StringLength); i += _namespace.UTF8StringLength; cString[i++] = '\''; + + defaultNS = _namespace; } /* Attributes */ for (OFXMLAttribute *attribute in _attributes) { void *pool2 = objc_autoreleasePoolPush(); @@ -501,12 +520,12 @@ attribute.stringValue.stringByXMLEscaping; char delimiter = (attribute->_useDoubleQuotes ? '"' : '\''); if (attribute->_namespace != nil && - (attributePrefix = [allNS objectForKey: - attribute->_namespace]) == nil) + [(attributePrefix = [allNS objectForKey: + attribute->_namespace]) length] == 0) @throw [OFUnboundNamespaceException exceptionWithNamespace: attribute.namespace element: self]; length += attributeNameLength + (attributePrefix != nil @@ -561,19 +580,21 @@ if (ind) [tmp addItem: "\n"]; if ([child isKindOfClass: [OFXMLElement class]]) childString = [(OFXMLElement *)child - of_XMLStringWithParent: self - namespaces: allNS - indentation: ind - level: level + 1]; - else - childString = [child - XMLStringWithIndentation: ind - level: level + - 1]; + of_XMLStringWithDefaultNS: defaultNS + namespaces: allNS + indentation: ind + level: level + + 1]; + else { + childString = child.XMLString; + for (unsigned int j = 0; + j < ind * (level + 1); j++) + [tmp addItem: " "]; + } [tmp addItems: childString.UTF8String count: childString.UTF8StringLength]; } @@ -594,11 +615,11 @@ i += level * indentation; } cString[i++] = '<'; cString[i++] = '/'; - if (prefix != nil) { + if (prefix.length > 0) { length += prefix.UTF8StringLength + 1; cString = OFResizeMemory(cString, length, 1); memcpy(cString + i, prefix.UTF8String, prefix.UTF8StringLength); @@ -624,31 +645,31 @@ return ret; } - (OFString *)XMLString { - return [self of_XMLStringWithParent: nil - namespaces: nil - indentation: 0 - level: 0]; + return [self of_XMLStringWithDefaultNS: nil + namespaces: nil + indentation: 0 + level: 0]; } - (OFString *)XMLStringWithIndentation: (unsigned int)indentation { - return [self of_XMLStringWithParent: nil - namespaces: nil - indentation: indentation - level: 0]; + return [self of_XMLStringWithDefaultNS: nil + namespaces: nil + indentation: indentation + level: 0]; } -- (OFString *)XMLStringWithIndentation: (unsigned int)indentation - level: (unsigned int)level +- (OFString *)XMLStringWithDefaultNamespace: (OFString *)defaultNS + indentation: (unsigned int)indentation { - return [self of_XMLStringWithParent: nil - namespaces: nil - indentation: indentation - level: level]; + return [self of_XMLStringWithDefaultNS: defaultNS + namespaces: nil + indentation: indentation + level: 0]; } - (OFXMLElement *)XMLElementBySerializing { void *pool = objc_autoreleasePoolPush(); @@ -662,14 +683,10 @@ if (_namespace != nil) [element addAttributeWithName: @"namespace" stringValue: _namespace]; - if (_defaultNamespace != nil) - [element addAttributeWithName: @"defaultNamespace" - stringValue: _defaultNamespace]; - if (_attributes != nil) { OFXMLElement *attributesElement; attributesElement = [OFXMLElement elementWithName: @"attributes" @@ -814,12 +831,10 @@ - (void)setPrefix: (OFString *)prefix forNamespace: (OFString *)namespace { if (prefix.length == 0) @throw [OFInvalidArgumentException exception]; - if (namespace == nil) - namespace = @""; [_namespaces setObject: prefix forKey: namespace]; } - (void)bindPrefix: (OFString *)prefix forNamespace: (OFString *)namespace @@ -994,13 +1009,10 @@ if (element->_name != _name && ![element->_name isEqual: _name]) return false; if (element->_namespace != _namespace && ![element->_namespace isEqual: _namespace]) return false; - if (element->_defaultNamespace != _defaultNamespace && - ![element->_defaultNamespace isEqual: _defaultNamespace]) - return false; if (element->_attributes != _attributes && ![element->_attributes isEqual: _attributes]) return false; if (element->_namespaces != _namespaces && ![element->_namespaces isEqual: _namespaces]) @@ -1018,11 +1030,10 @@ OFHashInit(&hash); OFHashAddHash(&hash, _name.hash); OFHashAddHash(&hash, _namespace.hash); - OFHashAddHash(&hash, _defaultNamespace.hash); OFHashAddHash(&hash, _attributes.hash); OFHashAddHash(&hash, _namespaces.hash); OFHashAddHash(&hash, _children.hash); OFHashFinalize(&hash); @@ -1030,8 +1041,20 @@ return hash; } - (id)copy { - return [[[self class] alloc] initWithElement: self]; + OFXMLElement *copy = [[OFXMLElement alloc] of_init]; + @try { + copy->_name = [_name copy]; + copy->_namespace = [_namespace copy]; + copy->_attributes = [_attributes mutableCopy]; + copy->_namespaces = [_namespaces mutableCopy]; + copy->_children = [_children mutableCopy]; + } @catch (id e) { + [copy release]; + @throw e; + } + + return copy; } @end