Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -34,10 +34,11 @@ OFString+XMLUnescaping.m \ OFTCPSocket.m \ ${OFTHREAD_M} \ OFXMLAttribute.m \ OFXMLElement.m \ + OFXMLElementBuilder.m \ OFXMLParser.m \ unicode.m INCLUDES := ${SRCS:.m=.h} \ ObjFW.h \ ADDED src/OFXMLElementBuilder.h Index: src/OFXMLElementBuilder.h ================================================================== --- src/OFXMLElementBuilder.h +++ src/OFXMLElementBuilder.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "OFObject.h" + +@class OFMutableArray; +@class OFXMLElement; +@class OFXMLElementBuilder; + +/** + * \brief A protocol that needs to be implemented by delegates for + * OFXMLElementBuilder. + */ +@protocol OFXMLElementBuilderDelegate +/** + * This callback is called when the OFXMLElementBuilder built an element. + * + * If the OFXMLElementBuilder was used as a delegate for the OFXMLParser since + * parsing started, this will return the complete document as an OFXMLElement + * with all children. + * + * \param builder The builder which built an OFXMLElement + * \param elem The OFXMLElement the OFXMLElementBuilder built + */ +- (void)elementBuilder: (OFXMLElementBuilder*)builder + didBuildElement: (OFXMLElement*)elem; +@end + +/** + * \brief A class implementing the OFXMLParserDelegate protocol that can build + * OFXMLElements from the document parsed by the OFXMLParser. + * + * It can also be used to build OFXMLElements from parts of the document by + * first parsing stuff using the OFXMLParser with another delegate and then + * setting the OFXMLElementBuilder as delegate for the parser. + */ +@interface OFXMLElementBuilder: OFObject +{ + OFMutableArray *stack; + OFObject *delegate; +} + +#ifdef OF_HAVE_PROPERTIES +@property (retain) OFObject *delegate; +#endif + +/** + * \return A new, autoreleased OFXMLElementBuilder + */ ++ elementBuilder; + +/** + * \return The delegate for the OFXMLElementBuilder + */ +- (OFObject *)delegate; + +/** + * Sets the delegate for the OFXMLElementBuilder. + * + * \param delegate The delegate for the OFXMLElementBuilder + */ +- (void)setDelegate: (OFObject *)delegate; +@end ADDED src/OFXMLElementBuilder.m Index: src/OFXMLElementBuilder.m ================================================================== --- src/OFXMLElementBuilder.m +++ src/OFXMLElementBuilder.m @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include "config.h" + +#import "OFXMLElementBuilder.h" +#import "OFXMLElement.h" +#import "OFXMLParser.h" +#import "OFMutableArray.h" +#import "OFAutoreleasePool.h" + +@implementation OFXMLElementBuilder ++ elementBuilder +{ + return [[[self alloc] init] autorelease]; +} + +- init +{ + self = [super init]; + + stack = [[OFMutableArray alloc] init]; + + return self; +} + +- (void)dealloc +{ + [stack release]; + [delegate release]; + + [super dealloc]; +} + +- (OFObject *)delegate +{ + return [[delegate retain] autorelease]; +} + +- (void)setDelegate: (OFObject *)delegate_ +{ + [delegate_ retain]; + [delegate release]; + delegate = delegate_; +} + +- (void)parser: (OFXMLParser*)parser + didStartElement: (OFString*)name + withPrefix: (OFString*)prefix + namespace: (OFString*)ns + attributes: (OFArray*)attrs +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFXMLElement *elem; + OFXMLAttribute **attrs_c; + size_t i, attrs_cnt; + IMP add_attr; + + elem = [OFXMLElement elementWithName: name + namespace: ns]; + + attrs_c = [attrs cArray]; + attrs_cnt = [attrs count]; + add_attr = [elem methodForSelector: @selector(addAttribute:)]; + + for (i = 0; i < attrs_cnt; i++) { + add_attr(elem, @selector(addAttribute:), attrs_c[i]); + + if ([attrs_c[i] namespace] == nil && + [[attrs_c[i] name] isEqual: @"xmlns"]) + [elem setDefaultNamespace: [attrs_c[i] stringValue]]; + else if ([[attrs_c[i] namespace] + isEqual: @"http://www.w3.org/2000/xmlns/"]) + [elem setPrefix: [attrs_c[i] name] + forNamespace: [attrs_c[i] stringValue]]; + } + + [[stack lastObject] addChild: elem]; + [stack addObject: elem]; + + [pool release]; +} + +- (void)parser: (OFXMLParser*)parser + didEndElement: (OFString*)name + withPrefix: (OFString*)prefix + namespace: (OFString*)ns +{ + if ([stack count] == 1) + [delegate elementBuilder: self + didBuildElement: [stack firstObject]]; + + [stack removeNObjects: 1]; +} + +- (void)parser: (OFXMLParser*)parser + foundCharacters: (OFString*)str +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + [[stack lastObject] + addChild: [OFXMLElement elementWithCharacters: str]]; + [pool release]; +} + +- (void)parser: (OFXMLParser*)parser + foundCDATA: (OFString*)cdata +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + [[stack lastObject] addChild: [OFXMLElement elementWithCDATA: cdata]]; + [pool release]; +} + +- (void)parser: (OFXMLParser*)parser + foundComment: (OFString*)comment +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFXMLElement *last = [stack lastObject]; + + [last addChild: [OFXMLElement elementWithComment: comment]]; + + [pool release]; +} +@end Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -1,27 +1,28 @@ include ../extra.mk SUBDIRS = ${TESTPLUGIN} PROG_NOINST = tests${PROG_SUFFIX} -SRCS = OFArrayTests.m \ - OFDataArrayTests.m \ - OFDictionaryTests.m \ - OFFileTests.m \ - OFListTests.m \ - OFMD5HashTests.m \ - OFNumberTests.m \ - OFObjectTests.m \ - ${OFPLUGINTESTS_M} \ - OFSHA1HashTests.m \ - OFStreamTests.m \ - OFStringTests.m \ - OFTCPSocketTests.m \ - ${OFTHREADTESTS_M} \ - OFXMLElementTests.m \ - OFXMLParserTests.m \ - ${PROPERTIESTESTS_M} \ +SRCS = OFArrayTests.m \ + OFDataArrayTests.m \ + OFDictionaryTests.m \ + OFFileTests.m \ + OFListTests.m \ + OFMD5HashTests.m \ + OFNumberTests.m \ + OFObjectTests.m \ + ${OFPLUGINTESTS_M} \ + OFSHA1HashTests.m \ + OFStreamTests.m \ + OFStringTests.m \ + OFTCPSocketTests.m \ + ${OFTHREADTESTS_M} \ + OFXMLElementTests.m \ + OFXMLElementBuilderTests.m \ + OFXMLParserTests.m \ + ${PROPERTIESTESTS_M} \ TestsAppDelegate.m IPHONE_USER = mobile IPHONE_TMP = /tmp/objfw-test ADDED tests/OFXMLElementBuilderTests.m Index: tests/OFXMLElementBuilderTests.m ================================================================== --- tests/OFXMLElementBuilderTests.m +++ tests/OFXMLElementBuilderTests.m @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include "config.h" + +#include +#include + +#import "OFXMLElementBuilder.h" +#import "OFXMLParser.h" +#import "OFAutoreleasePool.h" + +#import "TestsAppDelegate.h" + +static OFString *module = @"OFXMLElementBuilder"; +static OFXMLElement *elem = nil; + +@implementation TestsAppDelegate (OFXMLElementBuilderTests) +- (void)elementBuilder: (OFXMLElementBuilder*)builder + didBuildElement: (OFXMLElement*)elem_ +{ + assert(elem == nil); + elem = [elem_ retain]; +} + +- (void)XMLElementBuilderTests +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFXMLParser *p = [OFXMLParser parser]; + OFXMLElementBuilder *builder = [OFXMLElementBuilder elementBuilder]; + const char *str = "barbaz" + " " + ""; + + [p setDelegate: builder]; + [builder setDelegate: self]; + + TEST(@"Building element from parsed XML", + R([p parseBuffer: str + withSize: strlen(str)]) && + elem != nil && !strcmp([[elem string] cString], str)) + + + [elem release]; + [pool drain]; +} +@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -8,10 +8,11 @@ * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ #import "OFApplication.h" +#import "OFXMLElementBuilder.h" #define TEST(test, cond) \ { \ [self outputTesting: test \ inModule: module]; \ @@ -129,8 +130,12 @@ @interface TestsAppDelegate (OFXMLElementTests) - (void)XMLElementTests; @end -@interface TestsAppDelegate (OFXMLParserTests) +@interface TestsAppDelegate (OFXMLElementBuilderTests) +- (void)XMLElementBuilderTests; +@end + +@interface TestsAppDelegate (OFXMLParserTests) - (void)XMLParserTests; @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -91,10 +91,11 @@ #ifdef OF_THREADS [self threadTests]; #endif [self XMLElementTests]; [self XMLParserTests]; + [self XMLElementBuilderTests]; #ifdef OF_PLUGINS [self pluginTests]; #endif #ifdef OF_HAVE_PROPERTIES [self propertiesTests];