Index: src/OFXMLElementBuilder.h ================================================================== --- src/OFXMLElementBuilder.h +++ src/OFXMLElementBuilder.h @@ -30,10 +30,33 @@ * \param builder The builder which built an OFXMLElement * \param elem The OFXMLElement the OFXMLElementBuilder built */ - (void)elementBuilder: (OFXMLElementBuilder*)builder didBuildElement: (OFXMLElement*)elem; + +/** + * This callback is called when the OFXMLElementBuilder gets a close tag which + * does not belong there. + * + * Most likely, the OFXMLElementBuilder was used to build XML only of a child + * of the root element and the root element was closed. Often the delegate is + * set to the OFXMLElementBuilder when a certain element is found, this can be + * used then to set the delegate back after that certain element has been + * closed. + * + * If this method is not implemented in the delegate, the default is to throw + * an OFMalformedXMLException. + * + * \param builder The builder which did not expect the close tag + * \param name The name of the close tag + * \param prefix The prefix of the close tag + * \param ns The namespace of the close tag + */ +- (void)elementBuilder: (OFXMLElementBuilder*)builder + didNotExpectCloseTag: (OFString*)name + withPrefix: (OFString*)prefix + namespace: (OFString*)ns; @end /** * \brief A class implementing the OFXMLParserDelegate protocol that can build * OFXMLElements from the document parsed by the OFXMLParser. @@ -67,5 +90,8 @@ * * \param delegate The delegate for the OFXMLElementBuilder */ - (void)setDelegate: (id )delegate; @end + +@interface OFObject (OFXMLElementBuilderDelegate) +@end Index: src/OFXMLElementBuilder.m ================================================================== --- src/OFXMLElementBuilder.m +++ src/OFXMLElementBuilder.m @@ -14,10 +14,11 @@ #import "OFXMLElementBuilder.h" #import "OFXMLElement.h" #import "OFXMLParser.h" #import "OFMutableArray.h" #import "OFAutoreleasePool.h" +#import "OFExceptions.h" @implementation OFXMLElementBuilder + elementBuilder { return [[[self alloc] init] autorelease]; @@ -97,10 +98,18 @@ - (void)parser: (OFXMLParser*)parser didEndElement: (OFString*)name withPrefix: (OFString*)prefix namespace: (OFString*)ns { + if ([stack count] == 0) { + [delegate elementBuilder: self + didNotExpectCloseTag: name + withPrefix: prefix + namespace: ns]; + return; + } + if ([stack count] == 1) [delegate elementBuilder: self didBuildElement: [stack firstObject]]; [stack removeNObjects: 1]; @@ -108,29 +117,61 @@ - (void)parser: (OFXMLParser*)parser foundCharacters: (OFString*)str { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - [[stack lastObject] - addChild: [OFXMLElement elementWithCharacters: str]]; + OFXMLElement *elem = [OFXMLElement elementWithCharacters: str]; + + if ([stack count] == 0) + [delegate elementBuilder: self + didBuildElement: elem]; + else + [[stack lastObject] addChild: elem]; + [pool release]; } - (void)parser: (OFXMLParser*)parser foundCDATA: (OFString*)cdata { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - [[stack lastObject] addChild: [OFXMLElement elementWithCDATA: cdata]]; + OFXMLElement *elem = [OFXMLElement elementWithCDATA: cdata]; + + if ([stack count] == 0) + [delegate elementBuilder: self + didBuildElement: elem]; + else + [[stack lastObject] addChild: elem]; + [pool release]; } - (void)parser: (OFXMLParser*)parser foundComment: (OFString*)comment { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - OFXMLElement *last = [stack lastObject]; + OFXMLElement *elem = [OFXMLElement elementWithComment: comment]; - [last addChild: [OFXMLElement elementWithComment: comment]]; + if ([stack count] == 0) + [delegate elementBuilder: self + didBuildElement: elem]; + else + [[stack lastObject] addChild: elem]; [pool release]; } @end + +@implementation OFObject (OFXMLElementBuilderDelegate) +- (void)elementBuilder: (OFXMLElementBuilder*)builder + didBuildElement: (OFXMLElement*)elem +{ +} + +- (void)elementBuilder: (OFXMLElementBuilder*)builder + didNotExpectCloseTag: (OFString*)name + withPrefix: (OFString*)prefix + namespace: (OFString*)ns +{ + @throw [OFMalformedXMLException newWithClass: [builder class]]; +} +@end Index: tests/OFXMLElementBuilderTests.m ================================================================== --- tests/OFXMLElementBuilderTests.m +++ tests/OFXMLElementBuilderTests.m @@ -19,18 +19,19 @@ #import "OFAutoreleasePool.h" #import "TestsAppDelegate.h" static OFString *module = @"OFXMLElementBuilder"; -static OFXMLElement *elem = nil; +static OFXMLElement *elem[2]; +static size_t i = 0; @implementation TestsAppDelegate (OFXMLElementBuilderTests) - (void)elementBuilder: (OFXMLElementBuilder*)builder didBuildElement: (OFXMLElement*)elem_ { - assert(elem == nil); - elem = [elem_ retain]; + assert(i < 2); + elem[i++] = [elem_ retain]; } - (void)XMLElementBuilderTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; @@ -41,13 +42,16 @@ ""; [p setDelegate: builder]; [builder setDelegate: self]; - TEST(@"Building element from parsed XML", + TEST(@"Building elements from parsed XML", R([p parseString: str]) && - elem != nil && [[elem stringValue] isEqual: str]) + elem[0] != nil && [[elem[0] stringValue] isEqual: str] && + R([p parseString: @""]) && + elem[1] != nil && [[elem[1] stringValue] isEqual: @""]) - [elem release]; + [elem[0] release]; + [elem[1] release]; [pool drain]; } @end