]> err.no Git - sope/blob - sope-xml/DOM/NSObject+QPEval.m
use Version file for install locations
[sope] / sope-xml / DOM / NSObject+QPEval.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo 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
9   later version.
10
11   OGo 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.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "NSObject+QPEval.h"
24 #include "common.h"
25
26 @interface NSObject(QPEvalPrivates)
27
28 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx;
29 - (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs;
30
31 - (void)takeValue:(id)_value forQueryPath:(NSString *)_qp;
32 - (id)valueForQueryPath:(NSString *)_qp;
33 - (NSException *)setQueryPathValue:(id)_value;
34 - (id)queryPathValue;
35
36 @end /* NSObject(QPEval) */
37
38
39 @implementation NSString(QP)
40
41 - (NSArray *)queryPathComponents {
42   NSMutableArray *pc;
43   unsigned i, len, s;
44   
45   if ([self rangeOfString:@"/"].length == 0)
46     return [NSArray arrayWithObject:self];
47   if ([self isEqualToString:@"/"])
48     return [NSArray arrayWithObject:self];
49   
50   pc  = [NSMutableArray arrayWithCapacity:8];
51   len = [self length];
52   i   = 0;
53
54   /* add root, if absolute path */
55   if ([self characterAtIndex:0] == '/') {
56     i++;
57     [pc addObject:@"/"];
58   }
59   
60   for (s = i; i < len; i++) {
61     if ([self characterAtIndex:i] == '/') {
62       unsigned plen;
63       NSString *p;
64       
65       plen = (i - s);
66       p = [self substringWithRange:NSMakeRange(s, plen)];
67       [pc addObject:p];
68       s = (i + 1); /* next component begins at idx right after '/' .. */
69     }
70     else if ([self characterAtIndex:i] == '{') {
71       unsigned j;
72       
73       for (j = (i + 1); j < len; j++) {
74         if ([self characterAtIndex:j] == '}') {
75           /* continue after closing brace .. */
76           i = j;
77           break;
78         }
79       }
80     }
81   }
82   if (s < i) {
83     NSString *p;
84     
85     p = [self substringWithRange:NSMakeRange(s, (i - s))];
86     [pc addObject:p];
87   }
88   
89   return pc;
90 }
91
92 @end /* NSString(QP) */
93
94 @implementation NSObject(QPEval)
95
96 /* special expressions */
97
98 - (id)queryPathRootObjectInContext:(id)_ctx {
99   return self;
100 }
101
102 /* query path evaluation */
103
104 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
105   unsigned len;
106   NSArray  *result;
107   
108   result = nil;
109
110   if ((len = [_pc length]) == 0)
111     return nil;
112   else if (len == 1) {
113     unichar c;
114     
115     c = [_pc characterAtIndex:0];
116     if (c == '/') {
117       id root = [self queryPathRootObjectInContext:_ctx];
118       result = root ? [NSArray arrayWithObject:root] : nil;
119     }
120     else if (c == '.')
121       result = [NSArray arrayWithObject:self];
122   }
123   else {
124   }
125   
126   NSLog(@"0x%08X<%@> eval QP '%@': %@", self, NSStringFromClass([self class]),
127         _pc, result);
128   
129   return result;
130 }
131
132 - (NSArray *)queryPathCursorArray {
133   return [NSArray arrayWithObject:self];
134 }
135 - (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs {
136   NSEnumerator      *pcs;
137   NSString          *pc;
138   NSAutoreleasePool *pool;
139   NSArray           *array;
140   NSMutableDictionary *ctx;
141   
142   pool = [[NSAutoreleasePool alloc] init];
143
144   ctx = [NSMutableDictionary dictionaryWithCapacity:16];
145
146   NSLog(@"eval PCs: %@", _pcs);
147   
148   array = [self queryPathCursorArray];
149   
150   pcs = [_pcs objectEnumerator];
151   while ((array != nil) && (pc = [pcs nextObject])) {
152     if ((array = [array evaluateQueryPathComponent:pc inContext:ctx]) == nil)
153       break;
154   }
155   
156   array = [array retain];
157   [pool release];
158   
159   return [array autorelease];
160 }
161
162 - (NSArray *)evaluateQueryPath:(NSString *)_path {
163   if ([_path rangeOfString:@"/"].length == 0)
164     return [self evaluateQueryPathComponents:[NSArray arrayWithObject:_path]];
165   
166   if ([_path isEqualToString:@"/"]) {
167     static NSArray *rootElem = nil;
168     if (rootElem == nil)
169       rootElem = [NSArray arrayWithObject:@"/"];
170     return [self evaluateQueryPathComponents:rootElem];
171   }
172   
173   return [self evaluateQueryPathComponents:[_path queryPathComponents]];
174 }
175
176 /* query KVC */
177
178 - (NSException *)setQueryPathValue:(id)_value {
179   if (_value == self)
180     return nil;
181   
182   return [NSException exceptionWithName:@"QueryPathEvalException"
183                       reason:@"cannot set query-path value on object"
184                       userInfo:nil];
185 }
186 - (id)queryPathValue {
187   return self;
188 }
189
190 - (void)takeValue:(id)_value forQueryPath:(NSString *)_qp {
191   [[[self evaluateQueryPath:_qp] setQueryPathValue:_value] raise];
192 }
193 - (id)valueForQueryPath:(NSString *)_qp {
194   return [[self evaluateQueryPath:_qp] queryPathValue];
195 }
196
197 @end /* NSObject(QPEval) */
198
199 @implementation NSArray(QPEval)
200
201 - (NSArray *)queryPathCursorArray {
202   return self;
203 }
204 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
205   unsigned i, j, count;
206   NSArray  *array;
207   id       *objs;
208   
209   if ((count = [self count]) == 0)
210     return [NSArray array];
211   
212   objs = calloc(count + 1, sizeof(id));
213   for (i = 0, j = 0; i < count; i++) {
214     id obj;
215     
216     obj = [self objectAtIndex:i];
217     obj = [obj evaluateQueryPathComponent:_pc inContext:_ctx];
218
219     if (obj) {
220       objs[j] = obj;
221       j++;
222     }
223   }
224   array = [NSArray arrayWithObjects:objs count:j];
225   if (objs) free(objs);
226   return array;
227 }
228
229 @end /* NSArray(QPEval) */
230
231 @implementation NSSet(QPEval)
232
233 - (NSArray *)evaluateQueryPathComponent:(NSString *)_pc inContext:(id)_ctx {
234   return [[self allObjects] evaluateQueryPathComponent:_pc inContext:(id)_ctx];
235 }
236 - (NSArray *)evaluateQueryPathComponents:(NSArray *)_pcs {
237   return [[self allObjects] evaluateQueryPathComponents:_pcs];
238 }
239
240 @end /* NSSet(QPEval) */