Rev 1006 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1005 | dev | 1 | package ak.zpath; |
2 | |||
3 | import java.util.List; |
||
4 | import java.util.ArrayList; |
||
5 | import java.text.ParseException; |
||
6 | |||
7 | public class PathCreator |
||
8 | { |
||
9 | private PathElement element; |
||
10 | private List elements; |
||
11 | private PathParser pathParser = new PathParser(); |
||
12 | |||
13 | public PathCreator() |
||
14 | { |
||
15 | } |
||
16 | |||
17 | public List createPath(String path) |
||
18 | throws ParseException |
||
19 | { |
||
20 | List tokens = pathParser.parse(path); |
||
21 | Token firstToken; |
||
22 | int pos = -1; |
||
23 | |||
24 | if(tokens.size() == 0) |
||
25 | throw new PathCreateException("Empty path", null); |
||
26 | |||
27 | firstToken = (Token)tokens.get(0); |
||
28 | elements = new ArrayList(); |
||
29 | |||
30 | if(firstToken.getType() == Token.TOKEN_SLASH) { |
||
31 | // the path starts with slash |
||
32 | PathElement slashElement = new PathElement(); |
||
33 | |||
34 | slashElement.setName("/"); |
||
35 | elements.add(slashElement); |
||
36 | pos = 0; |
||
37 | } |
||
38 | |||
39 | element = null; |
||
40 | stateElementStart(tokens, pos); |
||
41 | if(element != null) elements.add(element); // add the last element |
||
42 | |||
43 | return elements; |
||
44 | } |
||
45 | |||
46 | private int stateElementStart(List tokens, int pos) |
||
47 | throws PathCreateException |
||
48 | { |
||
49 | Token token = (Token)tokens.get(++pos); |
||
50 | |||
51 | if(element != null) elements.add(element); |
||
52 | element = new PathElement(); |
||
53 | |||
54 | switch(token.getType()) { |
||
55 | case Token.TOKEN_NAME: |
||
56 | element.setName(token.getValue()); |
||
57 | pos = stateElementName(tokens, pos); |
||
58 | break; |
||
59 | |||
60 | default: |
||
61 | throw new PathCreateException("Element name expected", token); |
||
62 | } |
||
63 | |||
64 | return pos; |
||
65 | } |
||
66 | |||
67 | private int stateElementName(List tokens, int pos) |
||
68 | throws PathCreateException |
||
69 | { |
||
70 | if(++pos >= tokens.size()) return pos; |
||
71 | |||
72 | Token token = (Token)tokens.get(pos); |
||
73 | |||
74 | switch(token.getType()) { |
||
75 | case Token.TOKEN_SLASH: |
||
76 | pos = stateElementStart(tokens, pos); |
||
77 | break; |
||
78 | |||
79 | case Token.TOKEN_OPEN_BRACKET: |
||
80 | pos = stateElementCondition(tokens, pos); |
||
81 | break; |
||
82 | |||
83 | case Token.TOKEN_SHARP: |
||
84 | pos = stateOperandText(tokens, pos); |
||
85 | break; |
||
86 | |||
87 | case Token.TOKEN_AT: |
||
88 | pos = stateOperandAttribute(tokens, pos); |
||
89 | break; |
||
90 | |||
91 | default: |
||
92 | throw new PathCreateException( |
||
93 | "Element condition or operand expected", token); |
||
94 | } |
||
95 | |||
96 | return pos; |
||
97 | } |
||
98 | |||
99 | private int stateOperandText(List tokens, int pos) |
||
100 | throws PathCreateException |
||
101 | { |
||
102 | Token token = (Token)tokens.get(++pos); |
||
103 | |||
104 | element.setFirstOperand(PathElement.OPERAND_TEXT, null); |
||
105 | |||
106 | switch(token.getType()) { |
||
107 | case Token.TOKEN_ASSIGN: |
||
108 | element.setOperation(PathElement.OPERATION_ASSIGN); |
||
109 | pos = stateSecondOperand(tokens, pos); |
||
110 | break; |
||
111 | |||
112 | case Token.TOKEN_APPEND: |
||
113 | element.setOperation(PathElement.OPERATION_APPEND); |
||
114 | pos = stateSecondOperand(tokens, pos); |
||
115 | break; |
||
116 | |||
117 | default: |
||
118 | throw new PathCreateException( |
||
119 | "Assign or append operation expected", token); |
||
120 | } |
||
121 | |||
122 | return pos; |
||
123 | } |
||
124 | |||
125 | private int stateOperandAttribute(List tokens, int pos) |
||
126 | throws PathCreateException |
||
127 | { |
||
128 | Token token = (Token)tokens.get(++pos); |
||
129 | |||
130 | switch(token.getType()) { |
||
131 | case Token.TOKEN_NAME: { |
||
132 | element.setFirstOperand(PathElement.OPERAND_ATTRIBUTE, token.getValue()); |
||
133 | token = (Token)tokens.get(++pos); |
||
134 | switch(token.getType()) { |
||
135 | case Token.TOKEN_ASSIGN: |
||
136 | element.setOperation(PathElement.OPERATION_ASSIGN); |
||
137 | pos = stateSecondOperand(tokens, pos); |
||
138 | break; |
||
139 | |||
140 | case Token.TOKEN_APPEND: |
||
141 | element.setOperation(PathElement.OPERATION_APPEND); |
||
142 | pos = stateSecondOperand(tokens, pos); |
||
143 | break; |
||
144 | |||
145 | default: |
||
146 | throw new PathCreateException( |
||
147 | "Assign or append operation expected", token); |
||
148 | } |
||
149 | break; |
||
150 | } |
||
151 | |||
152 | default: |
||
153 | throw new PathCreateException("Attribute name expected", token); |
||
154 | } |
||
155 | |||
156 | return pos; |
||
157 | } |
||
158 | |||
159 | private int stateSecondOperand(List tokens, int pos) |
||
160 | throws PathCreateException |
||
161 | { |
||
162 | Token token = (Token)tokens.get(++pos); |
||
163 | |||
164 | switch(token.getType()) { |
||
165 | case Token.TOKEN_VARIABLE: |
||
166 | element.setSecondOperand(PathElement.OPERAND_VARIABLE, token.getValue()); |
||
167 | if(pos < tokens.size() - 1) |
||
168 | throw new PathCreateException("Path end expected", token); |
||
169 | break; |
||
170 | |||
171 | case Token.TOKEN_STRING: |
||
172 | element.setSecondOperand(PathElement.OPERAND_STRING, token.getValue()); |
||
173 | if(pos < tokens.size() - 1) |
||
174 | throw new PathCreateException("Path end expected", token); |
||
175 | break; |
||
176 | |||
177 | default: |
||
178 | throw new PathCreateException("Second operand expected", token); |
||
179 | } |
||
180 | |||
181 | element.validateOperands(); // must be end of the path |
||
182 | |||
183 | return pos; |
||
184 | } |
||
185 | |||
186 | private int stateElementCondition(List tokens, int pos) |
||
187 | throws PathCreateException |
||
188 | { |
||
189 | Token token = (Token)tokens.get(++pos); |
||
190 | |||
191 | switch(token.getType()) { |
||
192 | case Token.TOKEN_NEW: |
||
193 | pos = stateNew(tokens, pos); |
||
194 | break; |
||
195 | |||
196 | case Token.TOKEN_SHARP: |
||
197 | case Token.TOKEN_AT: |
||
198 | pos = stateLogicalCondition(tokens, pos); |
||
199 | break; |
||
200 | |||
1006 | dev | 201 | case Token.TOKEN_INDEX: |
202 | pos = stateIndex(tokens, pos); |
||
203 | break; |
||
204 | |||
1005 | dev | 205 | default: |
206 | throw new PathCreateException("Element condition expected", token); |
||
207 | } |
||
208 | |||
209 | return pos; |
||
210 | } |
||
211 | |||
212 | private int stateLogicalCondition(List tokens, int pos) |
||
213 | throws PathCreateException |
||
214 | { |
||
215 | Token token = (Token)tokens.get(pos); // do not go to the next token |
||
216 | |||
217 | switch(token.getType()) { |
||
218 | case Token.TOKEN_SHARP: |
||
219 | pos = stateConditionText(tokens, pos); |
||
220 | break; |
||
221 | |||
222 | case Token.TOKEN_AT: |
||
223 | pos = stateConditionAttribute(tokens, pos); |
||
224 | break; |
||
225 | |||
226 | default: |
||
227 | throw new PathCreateException("Element condition expected", token); |
||
228 | } |
||
229 | |||
230 | return pos; |
||
231 | } |
||
232 | |||
1006 | dev | 233 | private int stateIndex(List tokens, int pos) |
234 | throws PathCreateException |
||
235 | { |
||
236 | Token token = (Token)tokens.get(pos); |
||
237 | |||
238 | try { |
||
239 | element.setIndex(Integer.parseInt(token.getValue())); |
||
240 | } |
||
241 | catch(NumberFormatException ex) { |
||
242 | throw new PathCreateException( |
||
243 | "Cannot parse '" + token.getValue() + "' as integer", token); |
||
244 | } |
||
245 | |||
246 | token = (Token)tokens.get(++pos); |
||
247 | |||
248 | switch(token.getType()) { |
||
249 | case Token.TOKEN_CLOSE_BRACKET: |
||
250 | pos = stateConditionEnd(tokens, pos); |
||
251 | break; |
||
252 | |||
253 | case Token.TOKEN_AND: |
||
254 | pos++; // go to next token for stateLogicalCondition |
||
255 | pos = stateLogicalCondition(tokens, pos); |
||
256 | break; |
||
257 | |||
258 | default: |
||
259 | throw new PathCreateException( |
||
260 | "End of conditions or next condition expected", token); |
||
261 | } |
||
262 | |||
263 | return pos; |
||
264 | } |
||
265 | |||
1005 | dev | 266 | private int stateConditionText(List tokens, int pos) |
267 | throws PathCreateException |
||
268 | { |
||
269 | Token token = (Token)tokens.get(++pos); |
||
270 | |||
271 | element.addCondition(); |
||
272 | element.setFirstCondition(PathElement.OPERAND_TEXT, null); |
||
273 | |||
274 | switch(token.getType()) { |
||
275 | case Token.TOKEN_EQUAL: |
||
276 | element.setConditionOperation(PathElement.OPERATION_EQUAL); |
||
277 | pos = stateConditionSecond(tokens, pos); |
||
278 | break; |
||
279 | |||
280 | default: |
||
281 | throw new PathCreateException("Compare operator expected", token); |
||
282 | } |
||
283 | |||
284 | return pos; |
||
285 | } |
||
286 | |||
287 | private int stateConditionAttribute(List tokens, int pos) |
||
288 | throws PathCreateException |
||
289 | { |
||
290 | Token token = (Token)tokens.get(++pos); |
||
291 | |||
292 | element.addCondition(); |
||
293 | |||
294 | switch(token.getType()) { |
||
295 | case Token.TOKEN_NAME: { |
||
296 | element.setFirstCondition( |
||
297 | PathElement.OPERAND_ATTRIBUTE, token.getValue()); |
||
298 | token = (Token)tokens.get(++pos); |
||
299 | switch(token.getType()) { |
||
300 | case Token.TOKEN_EQUAL: |
||
301 | element.setConditionOperation(PathElement.OPERATION_EQUAL); |
||
302 | pos = stateConditionSecond(tokens, pos); |
||
303 | break; |
||
304 | |||
1007 | dev | 305 | case Token.TOKEN_CLOSE_BRACKET: |
306 | pos = stateConditionEnd(tokens, pos); |
||
307 | break; |
||
308 | |||
309 | case Token.TOKEN_AND: |
||
310 | pos++; // go to next token for stateLogicalCondition |
||
311 | pos = stateLogicalCondition(tokens, pos); |
||
312 | break; |
||
313 | |||
1005 | dev | 314 | default: |
315 | throw new PathCreateException("Compare operation expected", token); |
||
316 | } |
||
317 | break; |
||
318 | } |
||
319 | |||
320 | default: |
||
321 | throw new PathCreateException("Attibute name expected", token); |
||
322 | } |
||
323 | |||
324 | return pos; |
||
325 | } |
||
326 | |||
327 | private int stateConditionSecond(List tokens, int pos) |
||
328 | throws PathCreateException |
||
329 | { |
||
330 | Token token = (Token)tokens.get(++pos); |
||
331 | switch(token.getType()) { |
||
332 | case Token.TOKEN_VARIABLE: |
||
333 | element.setSecondCondition( |
||
334 | PathElement.OPERAND_VARIABLE, token.getValue()); |
||
335 | break; |
||
336 | |||
337 | case Token.TOKEN_STRING: |
||
338 | element.setSecondCondition( |
||
339 | PathElement.OPERAND_STRING, token.getValue()); |
||
340 | break; |
||
341 | |||
342 | default: |
||
343 | throw new PathCreateException( |
||
344 | "Second condition operand expected", token); |
||
345 | } |
||
346 | element.validateCondition(); // must be end of condition |
||
347 | |||
348 | token = (Token)tokens.get(++pos); |
||
349 | switch(token.getType()) { |
||
350 | case Token.TOKEN_CLOSE_BRACKET: |
||
351 | pos = stateConditionEnd(tokens, pos); |
||
352 | break; |
||
353 | |||
354 | case Token.TOKEN_AND: |
||
355 | pos++; // go to next token for stateLogicalCondition |
||
356 | pos = stateLogicalCondition(tokens, pos); |
||
357 | break; |
||
358 | |||
359 | default: |
||
360 | throw new PathCreateException( |
||
361 | "End of conditions or next condition expected", token); |
||
362 | } |
||
363 | |||
364 | return pos; |
||
365 | } |
||
366 | |||
367 | private int stateNew(List tokens, int pos) |
||
368 | throws PathCreateException |
||
369 | { |
||
370 | Token token = (Token)tokens.get(++pos); |
||
371 | |||
372 | element.setNew(); |
||
373 | |||
374 | switch(token.getType()) { |
||
375 | case Token.TOKEN_CLOSE_BRACKET: |
||
376 | pos = stateConditionEnd(tokens, pos); |
||
377 | break; |
||
378 | |||
379 | default: |
||
380 | throw new PathCreateException("End of conditions expected", token); |
||
381 | } |
||
382 | |||
383 | return pos; |
||
384 | } |
||
385 | |||
386 | private int stateConditionEnd(List tokens, int pos) |
||
387 | throws PathCreateException |
||
388 | { |
||
389 | if(++pos >= tokens.size()) return pos; |
||
390 | |||
391 | Token token = (Token)tokens.get(pos); |
||
392 | |||
393 | switch(token.getType()) { |
||
394 | case Token.TOKEN_SLASH: |
||
395 | stateElementStart(tokens, pos); // start new path element |
||
396 | break; |
||
397 | |||
398 | case Token.TOKEN_SHARP: |
||
399 | pos = stateOperandText(tokens, pos); |
||
400 | break; |
||
401 | |||
402 | case Token.TOKEN_AT: |
||
403 | pos = stateOperandAttribute(tokens, pos); |
||
404 | break; |
||
405 | |||
406 | default: |
||
407 | throw new PathCreateException( |
||
408 | "End of element description expected", token); |
||
409 | } |
||
410 | |||
411 | return pos; |
||
412 | } |
||
413 | } |