Index: src/OFXMLElement.h ================================================================== --- src/OFXMLElement.h +++ src/OFXMLElement.h @@ -215,10 +215,15 @@ /** * \return An array with all children of the element */ - (OFArray*)children; +/** + * \return A string with the string value of all children concatenated + */ +- (OFString*)stringValue; + /** * \return A new autoreleased OFString representing the OFXMLElement as an * XML string */ - (OFString*)XMLString; Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -262,10 +262,46 @@ - (OFArray*)children { return [[children copy] autorelease]; } + +- (OFString*)stringValue +{ + OFAutoreleasePool *pool; + OFMutableString *ret; + OFXMLElement **children_c; + size_t i, count = [children count]; + + if (count == 0) + return @""; + + ret = [OFMutableString string]; + children_c = [children cArray]; + pool = [[OFAutoreleasePool alloc] init]; + + for (i = 0; i < count; i++) { + if (children_c[i]->characters != nil) + [ret appendString: children_c[i]->characters]; + else if (children_c[i]->cdata != nil) + [ret appendString: children_c[i]->cdata]; + else if (children_c[i]->comment == nil) { + [ret appendString: [children_c[i] stringValue]]; + [pool releaseObjects]; + } + } + + [pool release]; + + /* + * Class swizzle the string to be immutable. We declared the return type + * to be OFString*, so it can't be modified anyway. But not swizzling it + * would create a real copy each time -[copy] is called. + */ + ret->isa = [OFString class]; + return ret; +} - (OFString*)_XMLStringWithParent: (OFXMLElement*)parent { OFAutoreleasePool *pool, *pool2; char *str_c; Index: tests/OFXMLElementTests.m ================================================================== --- tests/OFXMLElementTests.m +++ tests/OFXMLElementTests.m @@ -114,10 +114,15 @@ @""] && R([elem[2] addChild: [OFXMLElement elementWithName: @"bar" namespace: @"urn:objfw:test"]]) && [[elem[2] XMLString] isEqual: @""]) + + TEST(@"+[elementWithXMLString:] and -[stringValue]", + [[[OFXMLElement elementWithXMLString: + @"foobazqux"] stringValue] isEqual: + @"foobarbazqux"]) TEST(@"-[elementsForName:namespace:]", (a = [elem[2] elementsForName: @"bar" namespace: @"urn:objfw:test"]) && [a count] == 1 && [[[a firstObject] XMLString] isEqual: Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -136,12 +136,12 @@ #endif [self URLTests]; #ifdef OF_THREADS [self HTTPRequestTests]; #endif - [self XMLElementTests]; [self XMLParserTests]; + [self XMLElementTests]; [self XMLElementBuilderTests]; #ifdef OF_PLUGINS [self pluginTests]; #endif #ifdef OF_HAVE_PROPERTIES