Index: src/OFXMLElement.h ================================================================== --- src/OFXMLElement.h +++ src/OFXMLElement.h @@ -10,10 +10,11 @@ */ #import "OFObject.h" @class OFString; +@class OFMutableString; @class OFMutableArray; @class OFMutableDictionary; @class OFXMLAttribute; @interface OFXMLElement: OFObject @@ -20,13 +21,14 @@ { OFString *name; OFString *namespace; OFString *defaultNamespace; OFMutableArray *attributes; - OFString *stringValue; OFMutableDictionary *namespaces; OFMutableArray *children; + OFString *text; + OFMutableString *comment; } /** * \param name The name for the element * \return A new autoreleased OFXMLElement with the specified element name @@ -60,10 +62,26 @@ */ + elementWithName: (OFString*)name namespace: (OFString*)ns stringValue: (OFString*)stringval; +/** + * Creates a new element, only consisting of the specified text. + * + * \param text The text the element represents + * \return A new autoreleased OFXMLElement consisting of the specified text + */ ++ elementWithText: (OFString*)text; + +/** + * Creates a new element, only consisting of the specified comment. + * + * \param comment The comment the element represents + * \return A new autoreleased OFXMLElement consisting of the specified comment + */ ++ elementWithComment: (OFString*)text; + /** * Initializes an already allocated OFXMLElement with the specified element * name. * * \param name The name for the element @@ -107,10 +125,28 @@ */ - initWithName: (OFString*)name namespace: (OFString*)ns stringValue: (OFString*)stringval; +/** + * Initializes an already allocated OFXMLElement so that it only consists of the + * specified text. + * + * \param text The text the element represents + * \return An initialized OFXMLElement consisting of the specified text + */ +- initWithText: (OFString*)text; + +/** + * Initializes an already allocated OFXMLElement so that it only consists of the + * specified comment. + * + * \param comment The comment the element represents + * \return An initialized OFXMLElement consisting of the specified comment + */ +- initWithComment: (OFString*)text; + /** * \return A new autoreleased OFString representing the OFXMLElement as an * XML string */ - (OFString*)string; Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -48,10 +48,20 @@ { return [[[self alloc] initWithName: name namespace: ns stringValue: stringval] autorelease]; } + ++ elementWithText: (OFString*)text +{ + return [[[self alloc] initWithText: text] autorelease]; +} + ++ elementWithComment: (OFString*)comment +{ + return [[[self alloc] initWithComment: comment] autorelease]; +} - init { @throw [OFNotImplementedException newWithClass: isa selector: _cmd]; @@ -86,31 +96,75 @@ { self = [super init]; name = [name_ copy]; namespace = [ns copy]; - stringValue = [stringval copy]; + + if (stringval != nil) { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];; + [self addChild: [OFXMLElement elementWithText: stringval]]; + [pool release]; + } namespaces = [[OFMutableDictionary alloc] initWithKeysAndObjects: @"http://www.w3.org/XML/1998/namespace", @"xml", @"http://www.w3.org/2000/xmlns/", @"xmlns", nil]; return self; } + +- initWithText: (OFString*)text_ +{ + self = [super init]; + + @try { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + text = [[text_ stringByXMLEscaping] retain]; + [pool release]; + } @catch (OFException *e) { + [self dealloc]; + @throw e; + } + + return self; +} + +- initWithComment: (OFString*)comment_ +{ + self = [super init]; + + @try { + comment = [[OFMutableString alloc] initWithString: @""]; + } @catch (OFException *e) { + [self dealloc]; + @throw e; + } + + return self; +} - (OFString*)_stringWithParentNamespaces: (OFDictionary*)parent_namespaces parentDefaultNamespace: (OFString*)parent_default_ns { - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init], *pool2; + OFAutoreleasePool *pool, *pool2; char *str_c; size_t len, i, j, attrs_count; OFString *prefix = nil; OFXMLAttribute **attrs_carray; OFString *ret, *tmp; OFMutableDictionary *all_namespaces; OFString *def_ns; + if (text != nil) + return [[text retain] autorelease]; + + if (comment != nil) + return [[comment retain] autorelease]; + + pool = [[OFAutoreleasePool alloc] init]; def_ns = (defaultNamespace != nil ? defaultNamespace : parent_default_ns); if (parent_namespaces != nil) { OFEnumerator *key_enum = [namespaces keyEnumerator]; @@ -210,31 +264,25 @@ [pool2 releaseObjects]; } /* Childen */ - if (stringValue != nil || children != nil) { - if (stringValue != nil) - tmp = [stringValue stringByXMLEscaping]; - else if (children != nil) { - OFXMLElement **children_carray = [children cArray]; - size_t children_count = [children count]; - IMP append; - - tmp = [OFMutableString string]; - append = [tmp methodForSelector: - @selector(appendCStringWithoutUTF8Checking:)]; - - for (j = 0; j < children_count; j++) - append(tmp, @selector( - appendCStringWithoutUTF8Checking:), - [[children_carray[j] - _stringWithParentNamespaces: - all_namespaces - parentDefaultNamespace: defaultNamespace] - cString]); - } + if (children != nil) { + OFXMLElement **children_carray = [children cArray]; + size_t children_count = [children count]; + IMP append; + + tmp = [OFMutableString string]; + append = [tmp methodForSelector: + @selector(appendCStringWithoutUTF8Checking:)]; + + for (j = 0; j < children_count; j++) + append(tmp, @selector( + appendCStringWithoutUTF8Checking:), + [[children_carray[j] + _stringWithParentNamespaces: all_namespaces + parentDefaultNamespace: defaultNamespace] cString]); len += [tmp cStringLength] + [name cStringLength] + 2; @try { str_c = [self resizeMemory: str_c toSize: len]; @@ -288,10 +336,14 @@ parentDefaultNamespace: nil]; } - (void)addAttribute: (OFXMLAttribute*)attr { + if (name == nil) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + if (attributes == nil) attributes = [[OFMutableArray alloc] init]; /* FIXME: Prevent having it twice! */ @@ -299,11 +351,17 @@ } - (void)addAttributeWithName: (OFString*)name_ stringValue: (OFString*)value { - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFAutoreleasePool *pool; + + if (name == nil) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + pool = [[OFAutoreleasePool alloc] init]; [self addAttribute: [OFXMLAttribute attributeWithName: name_ namespace: nil stringValue: value]]; [pool release]; } @@ -310,11 +368,17 @@ - (void)addAttributeWithName: (OFString*)name_ namespace: (OFString*)ns stringValue: (OFString*)value { - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFAutoreleasePool *pool; + + if (name == nil) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + pool = [[OFAutoreleasePool alloc] init]; [self addAttribute: [OFXMLAttribute attributeWithName: name_ namespace: ns stringValue: value]]; [pool release]; } @@ -323,11 +387,11 @@ /* TODO: Remove attribute */ - (void)setPrefix: (OFString*)prefix forNamespace: (OFString*)ns { - if (prefix == nil || [prefix isEqual: @""]) + if (name == nil || prefix == nil || [prefix isEqual: @""]) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; if (ns == nil) ns = @""; @@ -335,23 +399,31 @@ forKey: ns]; } - (OFString*)defaultNamespace { + if (name == nil) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + return [[defaultNamespace retain] autorelease]; } - (void)setDefaultNamespace: (OFString*)ns { + if (name == nil) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + OFString *old = defaultNamespace; defaultNamespace = [ns copy]; [old release]; } - (void)addChild: (OFXMLElement*)child { - if (stringValue != nil) + if (name == nil) @throw [OFInvalidArgumentException newWithClass: isa selector: _cmd]; if (children == nil) children = [[OFMutableArray alloc] init]; @@ -362,12 +434,13 @@ - (void)dealloc { [name release]; [namespace release]; [attributes release]; - [stringValue release]; [namespaces release]; [children release]; + [text release]; + [comment release]; [super dealloc]; } @end Index: tests/OFXMLElementTests.m ================================================================== --- tests/OFXMLElementTests.m +++ tests/OFXMLElementTests.m @@ -53,10 +53,18 @@ stringValue: @"x"]) && R([elem[3] setPrefix: @"objfw-test" forNamespace: @"urn:objfw:test"]) && [[elem[3] string] isEqual: @"x"]) + TEST(@"+[elementWithText:]", + (elem[3] = [OFXMLElement elementWithText: @""]) && + [[elem[3] string] isEqual: @"<foo>"]) + + TEST(@"+[elementWithComment:]", + (elem[3] = [OFXMLElement elementWithComment: @" comment "]) && + [[elem[3] string] isEqual: @""]) + TEST(@"-[addAttributeWithName:stringValue:]", R([elem[0] addAttributeWithName: @"foo" stringValue: @"b&ar"]) && [[elem[0] string] isEqual: @""] && R([elem[1] addAttributeWithName: @"foo"