2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NSObject+QPEval.h"
25 @interface NSObject(QPEvalPrivates)
27 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx;
28 - (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs;
30 - (void)takeValue:(id)_value forQueryPath:(NSString *)_qp;
31 - (id)valueForQueryPath:(NSString *)_qp;
32 - (NSException *)setQueryPathValue:(id)_value;
35 @end /* NSObject(QPEval) */
38 @implementation NSString(QP)
40 - (NSArray *)queryPathComponents {
44 if ([self rangeOfString:@"/"].length == 0)
45 return [NSArray arrayWithObject:self];
46 if ([self isEqualToString:@"/"])
47 return [NSArray arrayWithObject:self];
49 pc = [NSMutableArray arrayWithCapacity:8];
53 /* add root, if absolute path */
54 if ([self characterAtIndex:0] == '/') {
59 for (s = i; i < len; i++) {
60 if ([self characterAtIndex:i] == '/') {
65 p = [self substringWithRange:NSMakeRange(s, plen)];
67 s = (i + 1); /* next component begins at idx right after '/' .. */
69 else if ([self characterAtIndex:i] == '{') {
72 for (j = (i + 1); j < len; j++) {
73 if ([self characterAtIndex:j] == '}') {
74 /* continue after closing brace .. */
84 p = [self substringWithRange:NSMakeRange(s, (i - s))];
91 @end /* NSString(QP) */
93 @implementation NSObject(QPEval)
95 /* special expressions */
97 - (id)queryPathRootObjectInContext:(id)_ctx {
101 /* query path evaluation */
103 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
109 if ((len = [_pc length]) == 0)
114 c = [_pc characterAtIndex:0];
116 id root = [self queryPathRootObjectInContext:_ctx];
117 result = root ? [NSArray arrayWithObject:root] : nil;
120 result = [NSArray arrayWithObject:self];
125 NSLog(@"0x%p<%@> eval QP '%@': %@", self, NSStringFromClass([self class]),
131 - (NSArray *)queryPathCursorArray {
132 return [NSArray arrayWithObject:self];
134 - (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs {
137 NSAutoreleasePool *pool;
139 NSMutableDictionary *ctx;
141 pool = [[NSAutoreleasePool alloc] init];
143 ctx = [NSMutableDictionary dictionaryWithCapacity:16];
145 NSLog(@"eval PCs: %@", _pcs);
147 array = [self queryPathCursorArray];
149 pcs = [_pcs objectEnumerator];
150 while ((array != nil) && (pc = [pcs nextObject])) {
151 if ((array = [array evaluateQueryPathComponent:pc inContext:ctx]) == nil)
155 array = [array retain];
158 return [array autorelease];
161 - (NSArray *)evaluateQueryPath:(NSString *)_path {
162 if ([_path rangeOfString:@"/"].length == 0)
163 return [self evaluateQueryPathComponents:[NSArray arrayWithObject:_path]];
165 if ([_path isEqualToString:@"/"]) {
166 static NSArray *rootElem = nil;
168 rootElem = [NSArray arrayWithObject:@"/"];
169 return [self evaluateQueryPathComponents:rootElem];
172 return [self evaluateQueryPathComponents:[_path queryPathComponents]];
177 - (NSException *)setQueryPathValue:(id)_value {
181 return [NSException exceptionWithName:@"QueryPathEvalException"
182 reason:@"cannot set query-path value on object"
185 - (id)queryPathValue {
189 - (void)takeValue:(id)_value forQueryPath:(NSString *)_qp {
190 [[[self evaluateQueryPath:_qp] setQueryPathValue:_value] raise];
192 - (id)valueForQueryPath:(NSString *)_qp {
193 return [[self evaluateQueryPath:_qp] queryPathValue];
196 @end /* NSObject(QPEval) */
198 @implementation NSArray(QPEval)
200 - (NSArray *)queryPathCursorArray {
203 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
204 unsigned i, j, count;
208 if ((count = [self count]) == 0)
209 return [NSArray array];
211 objs = calloc(count + 1, sizeof(id));
212 for (i = 0, j = 0; i < count; i++) {
215 obj = [self objectAtIndex:i];
216 obj = [obj evaluateQueryPathComponent:_pc inContext:_ctx];
223 array = [NSArray arrayWithObjects:objs count:j];
224 if (objs) free(objs);
228 @end /* NSArray(QPEval) */
230 @implementation NSSet(QPEval)
232 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
233 return [[self allObjects] evaluateQueryPathComponent:_pc inContext:(id)_ctx];
235 - (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs {
236 return [[self allObjects] evaluateQueryPathComponents:_pcs];
239 @end /* NSSet(QPEval) */