]> err.no Git - sope/commitdiff
enhanced .wo parser to use WO/# tag attributes as associations
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Tue, 6 Sep 2005 14:08:37 +0000 (14:08 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Tue, 6 Sep 2005 14:08:37 +0000 (14:08 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1101 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-appserver/NGObjWeb/ChangeLog
sope-appserver/NGObjWeb/Templates/WOHTMLParser.m
sope-appserver/NGObjWeb/Templates/WOWrapperTemplateBuilder.m
sope-appserver/NGObjWeb/Templates/WOxElemBuilder.m
sope-appserver/NGObjWeb/Version
sope-appserver/samples/HelloWorld/ChangeLog
sope-appserver/samples/HelloWorld/Main.m
sope-appserver/samples/HelloWorld/Main.wo/Main.html

index 32c1819eafeef2133a145afdc915e7197061bd30..94a2d871c00072b5af21283f721987c4486d78ee 100644 (file)
@@ -1,5 +1,20 @@
 2005-09-06  Helge Hess  <helge.hess@skyrix.com>
 
+       * v4.5.197
+
+       * Templates/WOWrapperTemplateBuilder.m: attributes of <WEBOBJECT> 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)
index 420de19de67457e33edc7186b37273394a33dea4..1e090e0cf43c7d085ef4d3cdaa9fd914cdf3da2e 100644 (file)
@@ -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 ('<#/' => '</#')."];
   }
   
+  /* parse tag name */
+  
   if ((name = _parseStringValue(_zone, _buffer, _idx,_len,_exc,self)) == nil) {
 #if HEAVY_DEBUG
     [self errorWithFormat:@"got no name for hash tag '<#NAME>'"];
@@ -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;
   }
   
index 838727c448645fa4a186599c83b124a03b9db0ff..bf56967f22887a0ebac17bfcd351eb5cedb1b0b9 100644 (file)
@@ -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"]) /* <WEBOBJECT 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" />
+         <WEBOBJECT NAME="WOString" var:value="abc"></WEBOBJECT>
+    */
+    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
index ff9362ce28bc8be118935e2d7705f79c1e327465..b1a729a641df44b8741e8a6e3baf78de41ceb22e 100644 (file)
@@ -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;
     
index 32c56ce20a746efd9d5ffb53e70a7129e150c9b2..0af1b101c778e320539a23cd8fb50033a363fd10 100644 (file)
@@ -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
index 994941ac8d4635b0e6f84cfcc6263290eccf0696..ed4475b078e7876f46417d3e6cace5017d950946 100644 (file)
@@ -1,3 +1,9 @@
+2005-09-06  Helge Hess  <helge.hess@skyrix.com>
+
+       * Main.wo/Main.html: added test for inline attributes
+
+       * Main.m: fixed a gcc4 warning
+
 2004-11-16  Helge Hess  <helge.hess@opengroupware.org>
 
        * GNUmakefile.preamble: fixed for FHS setups
index 0817fc066032428d3200b0c54618140bf4cd6eff..04c71802e070f43aaa7084fbb6ec2cf1c87af3e9 100644 (file)
@@ -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];
index bbca2e38cccc499fa51a7c5932d6f841ad784a08..1e40a46b2606ba7f89e954355c6f49ba1eb6786d 100644 (file)
@@ -9,6 +9,7 @@
 
     Application Name: 
     <#AppName/> (Hash),
-    <WEBOBJECT NAME="AppName"></WEBOBJECT> (WO)
+    <WEBOBJECT NAME="AppName"></WEBOBJECT> (WO),
+    <#WOString var:value="application.name" /> (Inline).
   </BODY>
 </HTML>