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