Created
August 15, 2018 03:44
-
-
Save wildthink/540079997e48c06915cdf3078b2b8308 to your computer and use it in GitHub Desktop.
Tagged Attribute Langage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSXMLNode+TAL.h | |
// WTTAL | |
// | |
// Created by Jason Jobe on 10/29/05. | |
// Copyright (c) 2005, 2013 Jason Jobe. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@class TALContext; | |
@interface NSXMLDocument (TALExtensions) | |
- initWithContentsOfFile:(NSString*)filename; | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context delegate:anObject; | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context; | |
// Output | |
- (NSData*)XMLDataWithOptions:(unsigned int)options omitRoot:(BOOL)flag; | |
- (NSString *)XMLStringWithOptions:(unsigned int)options omitRoot:(BOOL)flag; | |
@end | |
@interface NSXMLElement (TALExtensions) | |
+ (void)setDebugTaggedAttributeProcessing:(BOOL)flag; | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context delegate:anObject; | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context; | |
- (void)processTaggedAttributesWithTALContext:(TALContext*)context; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSXMLNode+TAL.m | |
// WTTAL | |
// | |
// Created by Jason Jobe on 10/29/05. | |
// Copyright (c) 2005, 2013 Jason Jobe. All rights reserved. | |
// | |
#import "NSXMLNode+TAL.h" | |
#import "TALContext.h" | |
#import "WTIterator.h" | |
static BOOL g_tal_debug = NO; | |
@interface NSObject (TALContextDelegate) | |
-(NSXMLElement*)processTaggedAttribute:(NSXMLNode*)node | |
forElement:(NSXMLElement*)element inTALContext:(TALContext*)context; | |
@end | |
@implementation NSXMLElement (TALExtensions) | |
+(void)setDebugTaggedAttributeProcessing:(BOOL)flag | |
{ | |
g_tal_debug = flag; | |
} | |
- (NSDictionary*)parseTALAttributes:(NSString*)str | |
{ | |
NSMutableDictionary *attr = [[NSMutableDictionary alloc] init]; | |
NSScanner *scanner = [[NSScanner alloc] initWithString:str]; | |
NSString *key, *value; | |
NSCharacterSet *space = [NSCharacterSet whitespaceCharacterSet]; | |
while (! [scanner isAtEnd]) { | |
[scanner scanUpToCharactersFromSet:space intoString:&key]; | |
[scanner scanUpToString:@";" intoString:&value]; | |
[scanner scanString:@";" intoString:NULL]; | |
if (value && key) | |
[attr setValue:value forKey:key]; | |
} | |
return attr; | |
} | |
-(void)processTaggedAttributesWithTALContext:(TALContext*)context | |
forEach:(NSString*)ident inArray:(NSArray*)values | |
{ | |
// remove tal:repeat to avoid infinite loop | |
[self removeAttributeForName:context.TAL_repeat]; | |
NSXMLElement *parent = (NSXMLElement*)[self parent]; // get it before we detach | |
[self detach]; | |
[context initiateLoop:ident withArray:values]; | |
while ([context nextObjectForLoop:ident]) { | |
id nodeCopy = [self copy]; | |
[parent addChild:nodeCopy]; | |
[nodeCopy processTaggedAttributesWithTALContext:context]; | |
} | |
} | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context | |
{ | |
return [self processTaggedAttributesWithPrefix:prefix context:context delegate:nil]; | |
} | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context delegate:anObject; | |
{ | |
TALContext *tc = [[TALContext alloc] initWithValues:context prefix:prefix]; | |
[tc setDelegate:anObject]; | |
[self processTaggedAttributesWithTALContext:tc]; | |
return self; | |
} | |
- (void)processTaggedAttributesWithTALContext:(TALContext*)context; | |
{ | |
NSString *talCommand; | |
id value; | |
if ((talCommand = [[self attributeForName:context.TAL_condition] stringValue])) { | |
if ([talCommand length]) { | |
value = [context valueForKeyPath:talCommand]; | |
} else { | |
value = @"0"; | |
} | |
if ([value intValue] == 0) | |
[self detach]; | |
if (![context debug]) [self removeAttributeForName:context.TAL_condition]; | |
} | |
if ((talCommand = [[self attributeForName:context.TAL_repeat] stringValue])) { | |
NSArray *array = [talCommand componentsSeparatedByString:@" "]; | |
value = [context valueForKeyPath:[array objectAtIndex:1]]; | |
[self processTaggedAttributesWithTALContext:(TALContext*)context forEach:[array objectAtIndex:0] inArray:value]; | |
return; | |
} | |
if ((talCommand = [[self attributeForName:context.TAL_replace] stringValue])) { | |
if ((value = [context valueForKeyPath:talCommand])) { | |
NSXMLElement *parent = (NSXMLElement*)[self parent]; | |
NSUInteger myIndex = [self index]; // [[parent children] indexOfObject:self]; | |
NSXMLNode *node = [[NSXMLNode alloc] initWithKind:NSXMLTextKind]; | |
// node = [NSXMLNode textWithStringValue:value]; | |
//[node setStringValue:value]; | |
[node setObjectValue:value]; // treats value as a literal | |
[parent replaceChildAtIndex:myIndex withNode:node]; | |
} | |
return; | |
} | |
if ((talCommand = [[self attributeForName:context.TAL_content] stringValue])) { | |
value = [context valueForKeyPath:talCommand]; | |
[self setStringValue:value resolvingEntities:NO]; | |
if (![context debug]) [self removeAttributeForName:context.TAL_content]; | |
} | |
/* | |
if (talCommand = [[self attributeForName:context.TAL_cdata] stringValue]) { | |
value = [context valueForKeyPath:talCommand]; | |
[self set | |
[self setStringValue:value resolvingEntities:YES]; | |
if (![context debug]) [self removeAttributeForName:context.TAL_content]; | |
} | |
*/ | |
if ((talCommand = [[self attributeForName:context.TAL_include] stringValue])) { | |
NSXMLDocument *doc = [context loadContentsOfResource:talCommand]; | |
NSXMLElement *parent = (NSXMLElement*)[self parent]; | |
NSUInteger myIndex = [self index]; // [[parent children] indexOfObject:self]; | |
NSXMLElement *node = [doc rootElement]; | |
[node detach]; | |
[parent replaceChildAtIndex:myIndex withNode:node]; | |
[node processTaggedAttributesWithTALContext:context]; | |
return; | |
} | |
if ((talCommand = [[self attributeForName:context.TAL_attributes] stringValue]) && [talCommand length]) | |
{ | |
NSDictionary *attr = [self parseTALAttributes:talCommand]; | |
NSEnumerator *keyCurs = [attr keyEnumerator]; | |
NSString *key; | |
while (key = [keyCurs nextObject]) { | |
value = [context valueForKeyPath:[attr valueForKey:key]]; | |
NSXMLNode *attribute = [NSXMLNode attributeWithName:key stringValue:value]; | |
[self removeAttributeForName:key]; | |
[self addAttribute:attribute]; | |
} | |
if (![context debug]) [self removeAttributeForName:context.TAL_attributes]; | |
} | |
if ((talCommand = [[self attributeForName:context.TAL_omit] stringValue])) { | |
if ([talCommand length]) { | |
value = [context valueForKeyPath:talCommand]; | |
} else { | |
value = @"1"; | |
} | |
if ([value intValue] == 1) { | |
id parent = [self parent]; | |
NSUInteger ndx = [self index]; // [[parent children] indexOfObject:self]; | |
[self detach]; | |
NSEnumerator *curs = [[self children] objectEnumerator]; | |
NSXMLElement *node; | |
while (node = [curs nextObject]) { | |
[node detach]; | |
[parent insertChild:node atIndex:ndx]; | |
++ndx; | |
} | |
} | |
if (![context debug]) [self removeAttributeForName:context.TAL_omit]; | |
} | |
if (context.delegate) { | |
NSEnumerator *attrCurs = [[self attributes] objectEnumerator]; | |
NSXMLElement *node; | |
while (node = [attrCurs nextObject]) { | |
if ([[node name] hasPrefix:context.TAL_prefix]) | |
node = [context.delegate processTaggedAttribute:node forElement:self inTALContext:context]; | |
} | |
} | |
NSEnumerator *childCurs = [[self children] objectEnumerator]; | |
NSXMLElement *node; | |
while (node = [childCurs nextObject]) { | |
if ([node respondsToSelector:@selector(processTaggedAttributesWithTALContext:)]) | |
[node processTaggedAttributesWithTALContext:context]; | |
} | |
} | |
@end | |
@implementation NSXMLDocument (TALExtensions) | |
- initWithContentsOfFile:(NSString*)filename | |
{ | |
NSURL *url = [NSURL fileURLWithPath:filename]; | |
NSError *error; | |
self = [[[self class] alloc] | |
initWithContentsOfURL:url | |
options:(NSXMLDocumentTidyXML|NSXMLNodePrettyPrint) | |
error:&error]; | |
if (error) { | |
NSLog (@"ERROR: [NSXMLDocument initWithContentsOfFile:%@] => %@", filename, error); | |
} | |
return self; | |
} | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context | |
{ | |
return [self processTaggedAttributesWithPrefix:prefix context:context delegate:nil]; | |
} | |
- processTaggedAttributesWithPrefix:(NSString*)prefix context:context delegate:anObject; | |
{ | |
[[self rootElement] processTaggedAttributesWithPrefix:prefix context:context delegate:anObject]; | |
return self; | |
} | |
// Output | |
- (NSData*)XMLDataWithOptions:(unsigned int)options omitRoot:(BOOL)omitRoot; | |
{ | |
if (omitRoot) { | |
NSString *xmlStr = [self XMLStringWithOptions:options omitRoot:omitRoot]; | |
NSData *data = [xmlStr dataUsingEncoding:NSASCIIStringEncoding]; | |
return data; | |
} | |
else { | |
return [self XMLDataWithOptions:options]; | |
} | |
} | |
- (NSString *)XMLStringWithOptions:(unsigned int)options omitRoot:(BOOL)omitRoot; | |
{ | |
if (omitRoot) { | |
NSMutableString *xmlStr = [NSMutableString string]; | |
NSEnumerator *curs = [[[self rootElement] children] objectEnumerator]; | |
NSXMLNode *node; | |
while (node = [curs nextObject]) { | |
[xmlStr appendString:[node XMLStringWithOptions:options]]; | |
[xmlStr appendString:@"\n"]; | |
} | |
return xmlStr; | |
} | |
else { | |
return [[self rootElement] XMLStringWithOptions:options]; | |
} | |
} | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TALContext.h | |
// WTTAL | |
// | |
// Created by Jason Jobe on 1/23/07. | |
// Copyright (c) 2007, 2013 Jason Jobe. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
@interface TALContext : NSObject | |
{ | |
} | |
@property (strong, nonatomic) NSString *TAL_prefix; | |
@property (strong, nonatomic) NSString *TAL_condition; | |
@property (strong, nonatomic) NSString *TAL_content; | |
@property (strong, nonatomic) NSString *TAL_replace; | |
@property (strong, nonatomic) NSString *TAL_attributes; | |
@property (strong, nonatomic) NSString *TAL_omit; | |
@property (strong, nonatomic) NSString *TAL_include; | |
@property (strong, nonatomic) NSString *TAL_repeat; | |
@property (weak, nonatomic) id delegate; | |
@property (strong, nonatomic) NSMutableDictionary *defines; | |
@property (strong, nonatomic) NSMutableDictionary *loops; | |
@property (strong, nonatomic) NSMutableDictionary *values; | |
@property (assign, nonatomic) BOOL debug; | |
- initWithValues:(NSDictionary*)vals; | |
- initWithValues:(NSDictionary*)vals prefix:(NSString*)prefix; | |
- (void)initiateLoop:(NSString*)name withArray:(NSArray*)anArray; | |
- nextObjectForLoop:(NSString*)name; | |
- (NSString*)resourcePathForKey:(NSString*)key; | |
- (NSXMLDocument*)loadContentsOfResource:(NSString*)key; | |
-(void)setDelegate:anObject; | |
- delegate; | |
-(BOOL)debug; | |
// Template processing | |
-(NSXMLDocument*)documentUsingTemplate:(NSXMLDocument*)templateDoc; | |
-(NSXMLDocument*)documentUsingTemplateURL:(NSURL*)templateURL; | |
-(NSXMLDocument*)documentUsingTemplateURL:(NSURL*)url withValue:value forKey:(NSString*)key; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TALContext.m | |
// WTTAL | |
// | |
// Created by Jason Jobe on 1/23/07. | |
// Copyright (c) 2007, 2013 Jason Jobe. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import "TALContext.h" | |
#import "NSXMLNode+TAL.h" | |
#import "WTIterator.h" | |
//static NSString *TemplateMark = @"$"; | |
static NSString *TemplateRepeatKey = @"for"; | |
@implementation TALContext | |
- initWithValues:(NSDictionary*)vals; | |
{ | |
return [self initWithValues:vals prefix:@"tal"]; | |
} | |
- initWithValues:(NSDictionary*)vals prefix:(NSString*)prefix; | |
{ | |
if (prefix == nil) | |
prefix = @"tal"; | |
self.TAL_prefix = [[NSString alloc] initWithFormat:@"%@:", prefix]; | |
self.TAL_condition = [[NSString alloc] initWithFormat:@"%@:if", prefix]; | |
self.TAL_content = [[NSString alloc] initWithFormat:@"%@:content", prefix]; | |
self.TAL_replace = [[NSString alloc] initWithFormat:@"%@:replace", prefix]; | |
self.TAL_attributes = [[NSString alloc] initWithFormat:@"%@:attributes", prefix]; | |
self.TAL_omit = [[NSString alloc] initWithFormat:@"%@:omit-tag", prefix]; | |
self.TAL_include = [[NSString alloc] initWithFormat:@"%@:include", prefix]; | |
self.TAL_repeat = [[NSString alloc] initWithFormat:@"%@:%@", prefix, TemplateRepeatKey]; | |
_loops = [[NSMutableDictionary alloc] init]; | |
_defines = [[NSMutableDictionary alloc] init]; | |
_values = [vals mutableCopy]; | |
return self; | |
} | |
- (void)initiateLoop:(NSString*)name withArray:(NSArray*)anArray | |
{ | |
if ([_loops valueForKey:name]) { | |
NSLog (@"TAL Loop ERROR: loop %@ already in use", name); | |
return; | |
} | |
WTIterator *looper = [[WTIterator alloc] initWithArray:anArray]; | |
[_loops setValue:looper forKey:name]; | |
} | |
- nextObjectForLoop:(NSString*)name | |
{ | |
WTIterator *looper = [_loops valueForKey:name]; | |
id value = [looper nextObject]; | |
if (value) { | |
[_values setValue:value forKey:name]; | |
} else { | |
// clean up because we're DONE | |
[_loops removeObjectForKey:name]; | |
[_values removeObjectForKey:name]; | |
} | |
return value; | |
} | |
- valueForKeyPath:(NSString*)keypath | |
{ | |
// // having the mark indicates we have a template | |
// NSRange range = [keypath rangeOfString:TemplateMark]; | |
// if (range.location != NSNotFound) | |
// return [keypath stringWithTemplateValues:values]; | |
// else | |
return [super valueForKeyPath:keypath]; | |
} | |
- valueForKey:(NSString*)key; | |
{ | |
WTIterator *looper; | |
id value; | |
if ([key isEqualToString:TemplateRepeatKey]) { | |
return _loops; | |
} else if ((value = [_defines valueForKey:key])) { | |
return value; | |
} else if ((looper = [_loops valueForKey:key])) { | |
return [looper currentObject]; | |
} else { | |
// // having a mark indicates we have a template | |
// NSRange range = [key rangeOfString:TemplateMark]; | |
// if (range.location != NSNotFound) | |
// return [key stringWithTemplateValues:values]; | |
// // else | |
return [_values valueForKey:key]; | |
} | |
} | |
-(NSString*)resourcePathForKey:(NSString*)key | |
{ | |
// // having the mark indicates we have a template | |
// NSRange range = [key rangeOfString:TemplateMark]; | |
// if (range.location != NSNotFound) | |
// return [key stringWithTemplateValues:values]; | |
// else | |
return key; | |
} | |
- (NSXMLDocument*)loadContentsOfResource:(NSString*)key | |
{ | |
NSString *path = [self resourcePathForKey:key]; | |
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfFile:path]; | |
// NSString *prefix = [[TAL_prefix componentsSeparatedByString:@":"] objectAtIndex:0]; | |
// [doc processTaggedAttributesWithPrefix:prefix context:self]; | |
return doc; | |
} | |
// Template processing | |
-(NSXMLDocument*)documentUsingTemplate:(NSXMLDocument*)templateDoc | |
{ | |
// [templateDoc processTaggedAttributesWithPrefix:@"tal" context:self delegate:delegate]; | |
[[templateDoc rootElement] processTaggedAttributesWithTALContext:self]; | |
return templateDoc; | |
} | |
-(NSXMLDocument*)documentUsingTemplateURL:(NSURL*)url; | |
{ | |
NSXMLDocument *templateDoc; | |
NSError *error; | |
templateDoc = [[NSXMLDocument alloc] | |
initWithContentsOfURL:url | |
options:(NSXMLDocumentTidyXML|NSXMLNodePrettyPrint) error:&error]; | |
return [self documentUsingTemplate:templateDoc]; | |
} | |
-(NSXMLDocument*)documentUsingTemplateURL:(NSURL*)url withValue:value forKey:(NSString*)key | |
{ | |
NSXMLDocument *doc; | |
[_defines setValue:value forKey:key]; | |
doc = [self documentUsingTemplateURL:url]; | |
return doc; | |
} | |
@end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// WTIterator.h | |
// WTTAL | |
// | |
// Created by Jason Jobe on 10/30/05. | |
// Copyright (c) 2005, 2013 Jason Jobe. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
/* | |
The following information is available from a Loop Iterator: | |
index - repetition number, starting from zero. | |
number - repetition number, starting from one. | |
even - true for even-indexed repetitions (0, 2, 4, ...). | |
odd - true for odd-indexed repetitions (1, 3, 5, ...). | |
start - true for the starting repetition (index 0). | |
end - true for the ending, or final, repetition. | |
length - length of the sequence, which will be the total number of repetitions. | |
letter - count reps with lower-case letters: "a" - "z", "aa" - "az", "ba" - "bz", ..., "za" - "zz", "aaa" - "aaz", and so forth. | |
Letter - upper-case version of letter. | |
*/ | |
@interface WTIterator : NSObject | |
@property (strong, nonatomic) NSArray *objects; | |
@property (assign, nonatomic) NSUInteger nextIndex; | |
@property (assign, nonatomic) NSUInteger count; | |
+ iteratorWithArray:(NSArray*)nobs; | |
- initWithArray:(NSArray*)nobs; | |
-(BOOL)start; | |
-(BOOL)end; | |
-(BOOL)odd; | |
-(BOOL)even; | |
-(NSUInteger)index; | |
-(NSUInteger)number; | |
-(NSUInteger)length; | |
- currentObject; | |
- nextObject; | |
// -(NSString*)letter; | |
// -(NSString*)Letter; | |
// -(NSString*)romanLetter; | |
@end | |
@interface NSArray (WTIterator) | |
-(WTIterator*)iterator; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// WTIterator.m | |
// WTTAL | |
// | |
// Created by Jason Jobe on 10/30/05. | |
// Copyright (c) 2005, 2013 Jason Jobe. All rights reserved. | |
// | |
#import "WTIterator.h" | |
@implementation WTIterator | |
+ iteratorWithArray:(NSArray*)nobs { | |
return [[[self class] alloc] initWithArray:nobs]; | |
} | |
- initWithArray:(NSArray*)nobs | |
{ | |
self.objects = nobs; | |
self.count = [nobs count]; | |
return self; | |
} | |
-(BOOL)start { return (self.nextIndex == 1); } | |
-(BOOL)end { return (self.nextIndex == self.count); } | |
-(BOOL)odd { return (self.nextIndex % 2 ? YES : NO); } | |
-(BOOL)even { return (self.nextIndex % 2 ? NO : YES); } | |
-(NSUInteger)index { return self.nextIndex - 1; } | |
-(NSUInteger)number { return self.nextIndex; } | |
-(NSUInteger)length { return self.count; } | |
- nextObject | |
{ | |
if (self.nextIndex < self.count) | |
return [self.objects objectAtIndex:(self.nextIndex++)]; | |
else | |
return nil; | |
} | |
- currentObject | |
{ | |
NSInteger ndx; | |
if (self.nextIndex == 0) { | |
ndx = 0; | |
} else if (self.nextIndex -1 < self.count) { | |
ndx = self.nextIndex - 1; | |
} else { | |
ndx = -1; | |
} | |
return (ndx < 0 ? nil : [self.objects objectAtIndex:(self.nextIndex - 1)]); | |
} | |
@end | |
@implementation NSArray (WTIterator) | |
-(WTIterator*)iterator { | |
return [WTIterator iteratorWithArray:self]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment