From 0a37607d125a5fec4de6a32224997ea701171be4 Mon Sep 17 00:00:00 2001 From: helge Date: Tue, 6 Sep 2005 14:08:37 +0000 Subject: [PATCH] enhanced .wo parser to use WO/# tag attributes as associations git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1101 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-appserver/NGObjWeb/ChangeLog | 15 ++ .../NGObjWeb/Templates/WOHTMLParser.m | 38 ++++- .../Templates/WOWrapperTemplateBuilder.m | 143 ++++++++++++++++-- .../NGObjWeb/Templates/WOxElemBuilder.m | 3 +- sope-appserver/NGObjWeb/Version | 2 +- sope-appserver/samples/HelloWorld/ChangeLog | 6 + sope-appserver/samples/HelloWorld/Main.m | 5 +- .../samples/HelloWorld/Main.wo/Main.html | 3 +- 8 files changed, 191 insertions(+), 24 deletions(-) diff --git a/sope-appserver/NGObjWeb/ChangeLog b/sope-appserver/NGObjWeb/ChangeLog index 32c1819e..94a2d871 100644 --- a/sope-appserver/NGObjWeb/ChangeLog +++ b/sope-appserver/NGObjWeb/ChangeLog @@ -1,5 +1,20 @@ 2005-09-06 Helge Hess + * v4.5.197 + + * Templates/WOWrapperTemplateBuilder.m: attributes of or + <#Element> tags are now added as associations to dynamic elements. + The type of the association is determined by the prefix (hardcoded: + var, const, so, rsrc). Tag attributes have precedence over wod + associations so that you can define defaults in the .wod file and + override them in the .html template. + If the .wod file does not contain a definition for a given tagname, + the parser will now attempt to treat the tagname as a class (eg: + <#WOString var:value="name"/> now works w/o any .wod entry). + + * Templates/WOHTMLParser.m (_parseHashElement): parse attributes + defined in hash tags (eg <#abc value="abc"/>) + * DynamicElements/WOSwitchComponent.m, DynamicElements/WOComponentReference.m: minor code cleanups (v4.5.196) diff --git a/sope-appserver/NGObjWeb/Templates/WOHTMLParser.m b/sope-appserver/NGObjWeb/Templates/WOHTMLParser.m index 420de19d..1e090e0c 100644 --- a/sope-appserver/NGObjWeb/Templates/WOHTMLParser.m +++ b/sope-appserver/NGObjWeb/Templates/WOHTMLParser.m @@ -443,6 +443,11 @@ static NSString *_parseStringValue(NSZone *_zone, } } +static NSMutableDictionary * +_parseTagAttributes(NSZone *_zone, const unichar *_buffer, + unsigned *_idx, unsigned _len, + NSException **_exception, WOHTMLParser *self); + static WOElement *_parseHashElement(NSZone *_zone, const unichar *_buffer, unsigned *_idx, unsigned _len, NSException **_exc, @@ -461,6 +466,7 @@ static WOElement *_parseHashElement(NSZone *_zone, const unichar *_buffer, NSMutableArray *children = nil; NSString *name; NSDictionary *nameDict; + NSMutableDictionary *attrs; BOOL hadSlashAfterHash; if (*_idx >= _len) return nil; // EOF @@ -477,6 +483,8 @@ static WOElement *_parseHashElement(NSZone *_zone, const unichar *_buffer, [self warnWithFormat:@"typo in hash close tag ('<#/' => ''"]; @@ -484,8 +492,20 @@ static WOElement *_parseHashElement(NSZone *_zone, const unichar *_buffer, if (_exc != NULL && *_exc != nil) // if there was an error .. return nil; } - _skipSpaces(_buffer, _idx, _len); + + /* parse attributes */ + + attrs = _parseTagAttributes(_zone, _buffer, _idx, _len, _exc, self); + if (_exc != NULL) { + if (*_exc != nil) { + [name release]; name = nil; + return nil; // invalid tag attrs + } + } + + /* parse tag end (> or /) */ + if (*_idx >= _len) { *_exc = _makeHtmlException(*_exc, _buffer, *_idx, _len, @@ -523,7 +543,7 @@ static WOElement *_parseHashElement(NSZone *_zone, const unichar *_buffer, NSLog(@" parsed subelement '%@' ..", subElement); #endif - if (subElement) { + if (subElement != nil) { if (children == nil) children = [NSMutableArray arrayWithCapacity:10]; [children addObject:subElement]; @@ -557,8 +577,11 @@ static WOElement *_parseHashElement(NSZone *_zone, const unichar *_buffer, nameDict = [[NSDictionary alloc] initWithObjects:&name forKeys:&nameKey count:1]; + if (attrs != nil) + [attrs addEntriesFromDictionary:nameDict]; + element = [self dynamicElementWithName:name - attributes:nameDict + attributes:(attrs != nil ? attrs : nameDict) contentElements:children]; [name release]; name = nil; [nameDict release]; nameDict = nil; @@ -690,10 +713,11 @@ static WOElement *_parseWOElement(NSZone *_zone, const unichar *_buffer, attrs = _parseTagAttributes(_zone, _buffer, _idx, _len, _exception, self); if (attrs == nil) { - //[self errorWithFormat: - // @"got no attributes for WO tag (need at least 'NAME').."]; - - if (_exception) // if there was an error .. +#if 0 + [self errorWithFormat: + @"got no attributes for WO tag (need at least 'NAME').."]; +#endif + if (_exception != NULL) // if there was an error .. // TODO: check this! return nil; } diff --git a/sope-appserver/NGObjWeb/Templates/WOWrapperTemplateBuilder.m b/sope-appserver/NGObjWeb/Templates/WOWrapperTemplateBuilder.m index 838727c4..bf56967f 100644 --- a/sope-appserver/NGObjWeb/Templates/WOWrapperTemplateBuilder.m +++ b/sope-appserver/NGObjWeb/Templates/WOWrapperTemplateBuilder.m @@ -57,8 +57,9 @@ + (BOOL)isDynamicElement; @end -static Class AssocClass = Nil; -static Class StrClass = Nil; +static Class AssocClass = Nil; +static Class StrClass = Nil; +static Class ValAssoc = Nil; @implementation WOWrapperTemplateBuilder @@ -66,6 +67,7 @@ static BOOL debugOn = NO; static BOOL logExtraAssociations = NO; static BOOL logScriptAdditions = NO; static NSStringEncoding parserEncoding; +static NSDictionary *defaultAssocMap = nil; + (int)version { return [super version] + 0 /* v2 */; @@ -79,6 +81,12 @@ static NSStringEncoding parserEncoding; AssocClass = [WOAssociation class]; StrClass = [NSString class]; + + if (ValAssoc == Nil) + ValAssoc = NSClassFromString(@"WOValueAssociation"); + + // TODO: improve extensibility of this (remember WOxElemBuilder) + defaultAssocMap = [[ud dictionaryForKey:@"WOxAssociationClassMapping"] copy]; if ([ud boolForKey:@"WOParsersUseUTF8"]) { parserEncoding = NSUTF8StringEncoding; @@ -417,6 +425,98 @@ static NSStringEncoding parserEncoding; return [template autorelease]; } +/* creating associations from WO/hash tag attributes */ + +- (NSString *)namespaceURIForPrefix:(NSString *)_prefix { + unsigned int len; + + if ((len = [_prefix length]) == 0) + return nil; + + switch (len) { + case 2: + if ([_prefix isEqualToString:@"so"]) + return @"http://www.skyrix.com/od/so-lookup"; + break; + case 3: + if ([_prefix isEqualToString:@"var"]) + return @"http://www.skyrix.com/od/binding"; + break; + case 4: + if ([_prefix isEqualToString:@"rsrc"]) + return @"OGo:url"; + break; + case 5: + if ([_prefix isEqualToString:@"const"]) + return @"http://www.skyrix.com/od/constant"; + if ([_prefix isEqualToString:@"label"]) + return @"OGo:label"; + break; + } + [self errorWithFormat:@"found no namespace for prefix: '%@'", _prefix]; + return nil; +} + +- (Class)associationClassForNamespaceURI:(NSString *)_uri { + if (_uri == nil) + return ValAssoc; + + // TODO: WOxElemBuilder caches the classes + return NSClassFromString([defaultAssocMap objectForKey:_uri]); +} + +- (void)addAttributes:(NSDictionary *)_attrs + toAssociations:(NSMutableDictionary *)assocs +{ + NSEnumerator *e; + NSString *key; + unsigned count; + + if (_attrs == nil) + return; + if ((count = [_attrs count]) == 0) + return; + if (count == 1 && [_attrs objectForKey:@"NAME"] != nil) + return; + + e = [_attrs keyEnumerator]; + while ((key = [e nextObject]) != nil) { + BOOL doRelease; + id value; + + if ([key isEqualToString:@"NAME"]) /* , not in assocs */ + continue; + + value = [_attrs objectForKey:key]; + if (![value isKindOfClass:AssocClass]) { + NSRange r; + NSString *uri, *name; + Class clazz; + + r = [key rangeOfString:@":"]; + uri = [self namespaceURIForPrefix: + (r.length > 0) ? [key substringToIndex:r.location] : nil]; + name = (r.length > 0) + ? [key substringFromIndex:(r.location + r.length)] + : key; + + if ((clazz = [self associationClassForNamespaceURI:uri]) == nil) { + [self logWithFormat:@"ERROR: could not process tag attribute: %@",key]; + continue; + } + + value = [[clazz alloc] initWithString:value]; + key = name; + doRelease = YES; + } + else + doRelease = NO; + + [assocs setObject:value forKey:key]; + if (doRelease) [value release]; + } +} + /* HTML parser callbacks */ - (NSString *)_uniqueComponentNameForDefinitionWithName:(NSString *)_element { @@ -487,16 +587,32 @@ static NSStringEncoding parserEncoding; Class elementClass; NSMutableDictionary *assoc = nil; WODynamicElement *element; - + if ((def = [self->definitions objectForKey:_element]) == nil) { - [self errorWithFormat: - @"did not find definition of dynamic element '%@'", - _element]; - return [[NSClassFromString(@"WONoContentElement") alloc] - initWithElementName:_element - attributes:_attributes - contentElements:_subElements - componentDefinition:nil]; + /* + If there is no definition with the name, try to treat it as a + classname, eg: + <#WOString var:value="abc" /> + + */ + if ((elementClass = NSClassFromString(_element)) == nil) { + /* ok, we also do not have a matching class */ + + [self errorWithFormat: + @"did not find definition of dynamic element '%@'", + _element]; + return [[NSClassFromString(@"WONoContentElement") alloc] + initWithElementName:_element + attributes:_attributes + contentElements:_subElements + componentDefinition:nil]; + } + + /* setup fake WOD entry */ + def = [[[_WODFileEntry alloc] init] autorelease]; + def->componentName = [_element copy]; + def->associations = [[NSDictionary alloc] init]; + def->componentClass = elementClass; } if (![def isDynamicElement]) { @@ -510,7 +626,10 @@ static NSStringEncoding parserEncoding; NSAssert1(elementClass, @"got no class for element %@", def); assoc = [def->associations mutableCopy]; - + [self addAttributes:_attributes toAssociations:assoc]; + + /* create element */ + element = [[elementClass alloc] initWithName:_element associations:assoc diff --git a/sope-appserver/NGObjWeb/Templates/WOxElemBuilder.m b/sope-appserver/NGObjWeb/Templates/WOxElemBuilder.m index ff9362ce..b1a729a6 100644 --- a/sope-appserver/NGObjWeb/Templates/WOxElemBuilder.m +++ b/sope-appserver/NGObjWeb/Templates/WOxElemBuilder.m @@ -136,6 +136,7 @@ static NGLogger *logger = nil; if (logAssocCreation) [logger logWithFormat:@"association creation is logged!"]; + // TODO: improve extensibility of this (remember WOWrapperTemplateBuilder) defaultAssocMap = [[ud dictionaryForKey:@"WOxAssociationClassMapping"] copy]; if (defaultAssocMap == nil) [logger warnWithFormat: @@ -452,7 +453,7 @@ static NGLogger *logger = nil; self->nsToAssoc = [[NSMutableDictionary alloc] initWithCapacity:8]; e = [defaultAssocMap keyEnumerator]; - while ((ns = [e nextObject])) { + while ((ns = [e nextObject]) != nil) { NSString *className; Class clazz; diff --git a/sope-appserver/NGObjWeb/Version b/sope-appserver/NGObjWeb/Version index 32c56ce2..0af1b101 100644 --- a/sope-appserver/NGObjWeb/Version +++ b/sope-appserver/NGObjWeb/Version @@ -1,6 +1,6 @@ # version file -SUBMINOR_VERSION:=196 +SUBMINOR_VERSION:=197 # v4.5.122 requires libNGExtensions v4.5.153 # v4.5.91 requires libNGExtensions v4.5.134 diff --git a/sope-appserver/samples/HelloWorld/ChangeLog b/sope-appserver/samples/HelloWorld/ChangeLog index 994941ac..ed4475b0 100644 --- a/sope-appserver/samples/HelloWorld/ChangeLog +++ b/sope-appserver/samples/HelloWorld/ChangeLog @@ -1,3 +1,9 @@ +2005-09-06 Helge Hess + + * Main.wo/Main.html: added test for inline attributes + + * Main.m: fixed a gcc4 warning + 2004-11-16 Helge Hess * GNUmakefile.preamble: fixed for FHS setups diff --git a/sope-appserver/samples/HelloWorld/Main.m b/sope-appserver/samples/HelloWorld/Main.m index 0817fc06..04c71802 100644 --- a/sope-appserver/samples/HelloWorld/Main.m +++ b/sope-appserver/samples/HelloWorld/Main.m @@ -35,8 +35,8 @@ @implementation Main -- (id)initWithContext:(id)_ctx { - if ((self = [super initWithContext:_ctx])) { +- (id)initWithContext:(WOContext *)_ctx { + if ((self = [super initWithContext:_ctx]) != nil) { NSMutableArray *ma; int i; @@ -44,6 +44,7 @@ for (i = 0; i < 1000; i++) { char buf[16]; NSString *s; + sprintf(buf, "%i", i); s = [[NSString alloc] initWithCString:buf]; [ma addObject:s]; diff --git a/sope-appserver/samples/HelloWorld/Main.wo/Main.html b/sope-appserver/samples/HelloWorld/Main.wo/Main.html index bbca2e38..1e40a46b 100644 --- a/sope-appserver/samples/HelloWorld/Main.wo/Main.html +++ b/sope-appserver/samples/HelloWorld/Main.wo/Main.html @@ -9,6 +9,7 @@ Application Name: <#AppName/> (Hash), - (WO) + (WO), + <#WOString var:value="application.name" /> (Inline). -- 2.39.5