KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jxpath > ri > compiler > CoreFunction


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.commons.jxpath.ri.compiler;
17
18 import java.text.DecimalFormat JavaDoc;
19 import java.text.DecimalFormatSymbols JavaDoc;
20 import java.text.NumberFormat JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Locale JavaDoc;
23
24 import org.apache.commons.jxpath.JXPathContext;
25 import org.apache.commons.jxpath.JXPathException;
26 import org.apache.commons.jxpath.ri.Compiler;
27 import org.apache.commons.jxpath.ri.EvalContext;
28 import org.apache.commons.jxpath.ri.InfoSetUtil;
29 import org.apache.commons.jxpath.ri.model.NodePointer;
30
31 /**
32  * An element of the compile tree representing one of built-in functions
33  * like "position()" or "number()".
34  *
35  * @author Dmitri Plotnikov
36  * @version $Revision: 1.16 $ $Date: 2004/04/01 02:53:45 $
37  */

38 public class CoreFunction extends Operation {
39
40     private static final Double JavaDoc ZERO = new Double JavaDoc(0);
41     private int functionCode;
42
43     public CoreFunction(int functionCode, Expression args[]) {
44         super(args);
45         this.functionCode = functionCode;
46     }
47
48     public int getFunctionCode() {
49         return functionCode;
50     }
51     
52     protected String JavaDoc getFunctionName() {
53         switch (functionCode) {
54             case Compiler.FUNCTION_LAST :
55                 return "last";
56             case Compiler.FUNCTION_POSITION :
57                 return "position";
58             case Compiler.FUNCTION_COUNT :
59                 return "count";
60             case Compiler.FUNCTION_ID :
61                 return "id";
62             case Compiler.FUNCTION_LOCAL_NAME :
63                 return "local-name";
64             case Compiler.FUNCTION_NAMESPACE_URI :
65                 return "namespace-uri";
66             case Compiler.FUNCTION_NAME :
67                 return "name";
68             case Compiler.FUNCTION_STRING :
69                 return "string";
70             case Compiler.FUNCTION_CONCAT :
71                 return "concat";
72             case Compiler.FUNCTION_STARTS_WITH :
73                 return "starts-with";
74             case Compiler.FUNCTION_CONTAINS :
75                 return "contains";
76             case Compiler.FUNCTION_SUBSTRING_BEFORE :
77                 return "substring-before";
78             case Compiler.FUNCTION_SUBSTRING_AFTER :
79                 return "substring-after";
80             case Compiler.FUNCTION_SUBSTRING :
81                 return "substring";
82             case Compiler.FUNCTION_STRING_LENGTH :
83                 return "string-length";
84             case Compiler.FUNCTION_NORMALIZE_SPACE :
85                 return "normalize-space";
86             case Compiler.FUNCTION_TRANSLATE :
87                 return "translate";
88             case Compiler.FUNCTION_BOOLEAN :
89                 return "boolean";
90             case Compiler.FUNCTION_NOT :
91                 return "not";
92             case Compiler.FUNCTION_TRUE :
93                 return "true";
94             case Compiler.FUNCTION_FALSE :
95                 return "false";
96             case Compiler.FUNCTION_LANG :
97                 return "lang";
98             case Compiler.FUNCTION_NUMBER :
99                 return "number";
100             case Compiler.FUNCTION_SUM :
101                 return "sum";
102             case Compiler.FUNCTION_FLOOR :
103                 return "floor";
104             case Compiler.FUNCTION_CEILING :
105                 return "ceiling";
106             case Compiler.FUNCTION_ROUND :
107                 return "round";
108             case Compiler.FUNCTION_KEY :
109                 return "key";
110             case Compiler.FUNCTION_FORMAT_NUMBER:
111                 return "format-number";
112         }
113         return "unknownFunction" + functionCode + "()";
114     }
115
116     public Expression getArg1() {
117         return args[0];
118     }
119
120     public Expression getArg2() {
121         return args[1];
122     }
123
124     public Expression getArg3() {
125         return args[2];
126     }
127
128     public int getArgumentCount() {
129         if (args == null) {
130             return 0;
131         }
132         return args.length;
133     }
134
135     /**
136      * Returns true if any argument is context dependent or if
137      * the function is last(), position(), boolean(), local-name(),
138      * name(), string(), lang(), number().
139      */

140     public boolean computeContextDependent() {
141         if (super.computeContextDependent()) {
142             return true;
143         }
144
145         switch(functionCode) {
146             case Compiler.FUNCTION_LAST:
147             case Compiler.FUNCTION_POSITION:
148                 return true;
149
150             case Compiler.FUNCTION_BOOLEAN:
151             case Compiler.FUNCTION_LOCAL_NAME:
152             case Compiler.FUNCTION_NAME:
153             case Compiler.FUNCTION_NAMESPACE_URI:
154             case Compiler.FUNCTION_STRING:
155             case Compiler.FUNCTION_LANG:
156             case Compiler.FUNCTION_NUMBER:
157                 return args == null || args.length == 0;
158
159             case Compiler.FUNCTION_COUNT:
160             case Compiler.FUNCTION_ID:
161             case Compiler.FUNCTION_CONCAT:
162             case Compiler.FUNCTION_STARTS_WITH:
163             case Compiler.FUNCTION_CONTAINS:
164             case Compiler.FUNCTION_SUBSTRING_BEFORE:
165             case Compiler.FUNCTION_SUBSTRING_AFTER:
166             case Compiler.FUNCTION_SUBSTRING:
167             case Compiler.FUNCTION_STRING_LENGTH:
168             case Compiler.FUNCTION_NORMALIZE_SPACE:
169             case Compiler.FUNCTION_TRANSLATE:
170             case Compiler.FUNCTION_NOT:
171             case Compiler.FUNCTION_TRUE:
172             case Compiler.FUNCTION_FALSE:
173             case Compiler.FUNCTION_SUM:
174             case Compiler.FUNCTION_FLOOR:
175             case Compiler.FUNCTION_CEILING:
176             case Compiler.FUNCTION_ROUND:
177                 return false;
178                 
179             case Compiler.FUNCTION_FORMAT_NUMBER:
180                 return args != null && args.length == 2;
181         }
182
183         return false;
184     }
185     
186     public String JavaDoc toString() {
187         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
188         buffer.append(getFunctionName());
189         buffer.append('(');
190         Expression args[] = getArguments();
191         if (args != null) {
192             for (int i = 0; i < args.length; i++) {
193                 if (i > 0) {
194                     buffer.append(", ");
195                 }
196                 buffer.append(args[i]);
197             }
198         }
199         buffer.append(')');
200         return buffer.toString();
201     }
202
203     public Object JavaDoc compute(EvalContext context) {
204         return computeValue(context);
205     }
206
207     /**
208      * Computes a built-in function
209      */

210     public Object JavaDoc computeValue(EvalContext context) {
211         switch (functionCode) {
212             case Compiler.FUNCTION_LAST :
213                 return functionLast(context);
214             case Compiler.FUNCTION_POSITION :
215                 return functionPosition(context);
216             case Compiler.FUNCTION_COUNT :
217                 return functionCount(context);
218             case Compiler.FUNCTION_LANG :
219                 return functionLang(context);
220             case Compiler.FUNCTION_ID :
221                 return functionID(context);
222             case Compiler.FUNCTION_LOCAL_NAME :
223                 return functionLocalName(context);
224             case Compiler.FUNCTION_NAMESPACE_URI :
225                 return functionNamespaceURI(context);
226             case Compiler.FUNCTION_NAME :
227                 return functionName(context);
228             case Compiler.FUNCTION_STRING :
229                 return functionString(context);
230             case Compiler.FUNCTION_CONCAT :
231                 return functionConcat(context);
232             case Compiler.FUNCTION_STARTS_WITH :
233                 return functionStartsWith(context);
234             case Compiler.FUNCTION_CONTAINS :
235                 return functionContains(context);
236             case Compiler.FUNCTION_SUBSTRING_BEFORE :
237                 return functionSubstringBefore(context);
238             case Compiler.FUNCTION_SUBSTRING_AFTER :
239                 return functionSubstringAfter(context);
240             case Compiler.FUNCTION_SUBSTRING :
241                 return functionSubstring(context);
242             case Compiler.FUNCTION_STRING_LENGTH :
243                 return functionStringLength(context);
244             case Compiler.FUNCTION_NORMALIZE_SPACE :
245                 return functionNormalizeSpace(context);
246             case Compiler.FUNCTION_TRANSLATE :
247                 return functionTranslate(context);
248             case Compiler.FUNCTION_BOOLEAN :
249                 return functionBoolean(context);
250             case Compiler.FUNCTION_NOT :
251                 return functionNot(context);
252             case Compiler.FUNCTION_TRUE :
253                 return functionTrue(context);
254             case Compiler.FUNCTION_FALSE :
255                 return functionFalse(context);
256             case Compiler.FUNCTION_NULL :
257                 return functionNull(context);
258             case Compiler.FUNCTION_NUMBER :
259                 return functionNumber(context);
260             case Compiler.FUNCTION_SUM :
261                 return functionSum(context);
262             case Compiler.FUNCTION_FLOOR :
263                 return functionFloor(context);
264             case Compiler.FUNCTION_CEILING :
265                 return functionCeiling(context);
266             case Compiler.FUNCTION_ROUND :
267                 return functionRound(context);
268             case Compiler.FUNCTION_KEY :
269                 return functionKey(context);
270             case Compiler.FUNCTION_FORMAT_NUMBER :
271                 return functionFormatNumber(context);
272         }
273         return null;
274     }
275
276     protected Object JavaDoc functionLast(EvalContext context) {
277         assertArgCount(0);
278         // Move the position to the beginning and iterate through
279
// the context to count nodes.
280
int old = context.getCurrentPosition();
281         context.reset();
282         int count = 0;
283         while (context.nextNode()) {
284             count++;
285         }
286
287         // Restore the current position.
288
if (old != 0) {
289             context.setPosition(old);
290         }
291         return new Double JavaDoc(count);
292     }
293
294     protected Object JavaDoc functionPosition(EvalContext context) {
295         assertArgCount(0);
296         return new Integer JavaDoc(context.getCurrentPosition());
297     }
298
299     protected Object JavaDoc functionCount(EvalContext context) {
300         assertArgCount(1);
301         Expression arg1 = getArg1();
302         int count = 0;
303         Object JavaDoc value = arg1.compute(context);
304         if (value instanceof NodePointer) {
305             value = ((NodePointer) value).getValue();
306         }
307         if (value instanceof EvalContext) {
308             EvalContext ctx = (EvalContext) value;
309             while (ctx.hasNext()) {
310                 ctx.next();
311                 count++;
312             }
313         }
314         else if (value instanceof Collection JavaDoc) {
315             count = ((Collection JavaDoc) value).size();
316         }
317         else if (value == null) {
318             count = 0;
319         }
320         else {
321             count = 1;
322         }
323         return new Double JavaDoc(count);
324     }
325
326     protected Object JavaDoc functionLang(EvalContext context) {
327         assertArgCount(1);
328         String JavaDoc lang = InfoSetUtil.stringValue(getArg1().computeValue(context));
329         NodePointer pointer = (NodePointer) context.getSingleNodePointer();
330         if (pointer == null) {
331             return Boolean.FALSE;
332         }
333         return pointer.isLanguage(lang) ? Boolean.TRUE : Boolean.FALSE;
334     }
335
336     protected Object JavaDoc functionID(EvalContext context) {
337         assertArgCount(1);
338         String JavaDoc id = InfoSetUtil.stringValue(getArg1().computeValue(context));
339         JXPathContext jxpathContext = context.getJXPathContext();
340         NodePointer pointer = (NodePointer) jxpathContext.getContextPointer();
341         return pointer.getPointerByID(jxpathContext, id);
342     }
343
344     protected Object JavaDoc functionKey(EvalContext context) {
345         assertArgCount(2);
346         String JavaDoc key = InfoSetUtil.stringValue(getArg1().computeValue(context));
347         String JavaDoc value = InfoSetUtil.stringValue(getArg2().computeValue(context));
348         JXPathContext jxpathContext = context.getJXPathContext();
349         NodePointer pointer = (NodePointer) jxpathContext.getContextPointer();
350         return pointer.getPointerByKey(jxpathContext, key, value);
351     }
352
353     protected Object JavaDoc functionNamespaceURI(EvalContext context) {
354         if (getArgumentCount() == 0) {
355             NodePointer ptr = context.getCurrentNodePointer();
356             String JavaDoc str = ptr.getNamespaceURI();
357             return str == null ? "" : str;
358         }
359         assertArgCount(1);
360         Object JavaDoc set = getArg1().compute(context);
361         if (set instanceof EvalContext) {
362             EvalContext ctx = (EvalContext) set;
363             if (ctx.hasNext()) {
364                 NodePointer ptr = (NodePointer) ctx.next();
365                 String JavaDoc str = ptr.getNamespaceURI();
366                 return str == null ? "" : str;
367             }
368         }
369         return "";
370     }
371
372     protected Object JavaDoc functionLocalName(EvalContext context) {
373         if (getArgumentCount() == 0) {
374             NodePointer ptr = context.getCurrentNodePointer();
375             return ptr.getName().getName();
376         }
377         assertArgCount(1);
378         Object JavaDoc set = getArg1().compute(context);
379         if (set instanceof EvalContext) {
380             EvalContext ctx = (EvalContext) set;
381             if (ctx.hasNext()) {
382                 NodePointer ptr = (NodePointer) ctx.next();
383                 return ptr.getName().getName();
384             }
385         }
386         return "";
387     }
388
389     protected Object JavaDoc functionName(EvalContext context) {
390         if (getArgumentCount() == 0) {
391             NodePointer ptr = context.getCurrentNodePointer();
392             return ptr.getName().toString();
393         }
394         assertArgCount(1);
395         Object JavaDoc set = getArg1().compute(context);
396         if (set instanceof EvalContext) {
397             EvalContext ctx = (EvalContext) set;
398             if (ctx.hasNext()) {
399                 NodePointer ptr = (NodePointer) ctx.next();
400                 return ptr.getName().toString();
401             }
402         }
403         return "";
404     }
405
406     protected Object JavaDoc functionString(EvalContext context) {
407         if (getArgumentCount() == 0) {
408             return InfoSetUtil.stringValue(context.getCurrentNodePointer());
409         }
410         assertArgCount(1);
411         return InfoSetUtil.stringValue(getArg1().computeValue(context));
412     }
413
414     protected Object JavaDoc functionConcat(EvalContext context) {
415         if (getArgumentCount() < 2) {
416             assertArgCount(2);
417         }
418         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
419         Expression args[] = getArguments();
420         for (int i = 0; i < args.length; i++) {
421             buffer.append(InfoSetUtil.stringValue(args[i].compute(context)));
422         }
423         return buffer.toString();
424     }
425
426     protected Object JavaDoc functionStartsWith(EvalContext context) {
427         assertArgCount(2);
428         String JavaDoc s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
429         String JavaDoc s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
430         return s1.startsWith(s2) ? Boolean.TRUE : Boolean.FALSE;
431     }
432
433     protected Object JavaDoc functionContains(EvalContext context) {
434         assertArgCount(2);
435         String JavaDoc s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
436         String JavaDoc s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
437         return s1.indexOf(s2) != -1 ? Boolean.TRUE : Boolean.FALSE;
438     }
439
440     protected Object JavaDoc functionSubstringBefore(EvalContext context) {
441         assertArgCount(2);
442         String JavaDoc s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
443         String JavaDoc s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
444         int index = s1.indexOf(s2);
445         if (index == -1) {
446             return "";
447         }
448         return s1.substring(0, index);
449     }
450
451     protected Object JavaDoc functionSubstringAfter(EvalContext context) {
452         assertArgCount(2);
453         String JavaDoc s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
454         String JavaDoc s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
455         int index = s1.indexOf(s2);
456         if (index == -1) {
457             return "";
458         }
459         return s1.substring(index + s2.length());
460     }
461
462     protected Object JavaDoc functionSubstring(EvalContext context) {
463         int ac = getArgumentCount();
464         if (ac != 2 && ac != 3) {
465             assertArgCount(2);
466         }
467
468         String JavaDoc s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
469         double from = InfoSetUtil.doubleValue(getArg2().computeValue(context));
470         if (Double.isNaN(from)) {
471             return "";
472         }
473
474         from = Math.round(from);
475         if (ac == 2) {
476             if (from < 1) {
477                 from = 1;
478             }
479             return s1.substring((int) from - 1);
480         }
481         else {
482             double length =
483                 InfoSetUtil.doubleValue(getArg3().computeValue(context));
484             length = Math.round(length);
485             if (length < 0) {
486                 return "";
487             }
488
489             double to = from + length;
490             if (to < 1) {
491                 return "";
492             }
493
494             if (to > s1.length() + 1) {
495                 if (from < 1) {
496                     from = 1;
497                 }
498                 return s1.substring((int) from - 1);
499             }
500
501             if (from < 1) {
502                 from = 1;
503             }
504             return s1.substring((int) from - 1, (int) (to - 1));
505         }
506     }
507
508     protected Object JavaDoc functionStringLength(EvalContext context) {
509         String JavaDoc s;
510         if (getArgumentCount() == 0) {
511             s = InfoSetUtil.stringValue(context.getCurrentNodePointer());
512         }
513         else {
514             assertArgCount(1);
515             s = InfoSetUtil.stringValue(getArg1().computeValue(context));
516         }
517         return new Double JavaDoc(s.length());
518     }
519
520     protected Object JavaDoc functionNormalizeSpace(EvalContext context) {
521         assertArgCount(1);
522         String JavaDoc s = InfoSetUtil.stringValue(getArg1().computeValue(context));
523         char chars[] = s.toCharArray();
524         int out = 0;
525         int phase = 0;
526         for (int in = 0; in < chars.length; in++) {
527             switch(chars[in]) {
528                 case 0x20:
529                 case 0x9:
530                 case 0xD:
531                 case 0xA:
532                     if (phase == 0) { // beginning
533
;
534                     }
535                     else if (phase == 1) { // non-space
536
phase = 2;
537                         chars[out++] = ' ';
538                     }
539                     break;
540                 default:
541                     chars[out++] = chars[in];
542                     phase = 1;
543             }
544         }
545         if (phase == 2) { // trailing-space
546
out--;
547         }
548         return new String JavaDoc(chars, 0, out);
549     }
550
551     protected Object JavaDoc functionTranslate(EvalContext context) {
552         assertArgCount(3);
553         String JavaDoc s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
554         String JavaDoc s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
555         String JavaDoc s3 = InfoSetUtil.stringValue(getArg3().computeValue(context));
556         char chars[] = s1.toCharArray();
557         int out = 0;
558         for (int in = 0; in < chars.length; in++) {
559             char c = chars[in];
560             int inx = s2.indexOf(c);
561             if (inx != -1) {
562                 if (inx < s3.length()) {
563                     chars[out++] = s3.charAt(inx);
564                 }
565             }
566             else {
567                 chars[out++] = c;
568             }
569         }
570         return new String JavaDoc(chars, 0, out);
571     }
572
573     protected Object JavaDoc functionBoolean(EvalContext context) {
574         assertArgCount(1);
575         return InfoSetUtil.booleanValue(getArg1().computeValue(context))
576             ? Boolean.TRUE
577             : Boolean.FALSE;
578     }
579
580     protected Object JavaDoc functionNot(EvalContext context) {
581         assertArgCount(1);
582         return InfoSetUtil.booleanValue(getArg1().computeValue(context))
583             ? Boolean.FALSE
584             : Boolean.TRUE;
585     }
586
587     protected Object JavaDoc functionTrue(EvalContext context) {
588         assertArgCount(0);
589         return Boolean.TRUE;
590     }
591
592     protected Object JavaDoc functionFalse(EvalContext context) {
593         assertArgCount(0);
594         return Boolean.FALSE;
595     }
596
597     protected Object JavaDoc functionNull(EvalContext context) {
598         assertArgCount(0);
599         return null;
600     }
601
602     protected Object JavaDoc functionNumber(EvalContext context) {
603         if (getArgumentCount() == 0) {
604             return InfoSetUtil.number(context.getCurrentNodePointer());
605         }
606         assertArgCount(1);
607         return InfoSetUtil.number(getArg1().computeValue(context));
608     }
609
610     protected Object JavaDoc functionSum(EvalContext context) {
611         assertArgCount(1);
612         Object JavaDoc v = getArg1().compute(context);
613         if (v == null) {
614             return ZERO;
615         }
616         else if (v instanceof EvalContext) {
617             double sum = 0.0;
618             EvalContext ctx = (EvalContext) v;
619             while (ctx.hasNext()) {
620                 NodePointer ptr = (NodePointer) ctx.next();
621                 sum += InfoSetUtil.doubleValue(ptr);
622             }
623             return new Double JavaDoc(sum);
624         }
625         throw new JXPathException(
626             "Invalid argument type for 'sum': " + v.getClass().getName());
627     }
628
629     protected Object JavaDoc functionFloor(EvalContext context) {
630         assertArgCount(1);
631         double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
632         return new Double JavaDoc(Math.floor(v));
633     }
634
635     protected Object JavaDoc functionCeiling(EvalContext context) {
636         assertArgCount(1);
637         double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
638         return new Double JavaDoc(Math.ceil(v));
639     }
640
641     protected Object JavaDoc functionRound(EvalContext context) {
642         assertArgCount(1);
643         double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
644         return new Double JavaDoc(Math.round(v));
645     }
646
647     private Object JavaDoc functionFormatNumber(EvalContext context) {
648         int ac = getArgumentCount();
649         if (ac != 2 && ac != 3) {
650             assertArgCount(2);
651         }
652
653         double number =
654             InfoSetUtil.doubleValue(getArg1().computeValue(context));
655         String JavaDoc pattern =
656             InfoSetUtil.stringValue(getArg2().computeValue(context));
657
658         DecimalFormatSymbols JavaDoc symbols = null;
659         if (ac == 3) {
660             String JavaDoc symbolsName =
661                 InfoSetUtil.stringValue(getArg3().computeValue(context));
662             symbols =
663                 context.getJXPathContext().getDecimalFormatSymbols(symbolsName);
664         }
665         else {
666             NodePointer pointer = context.getCurrentNodePointer();
667             Locale JavaDoc locale;
668             if (pointer != null) {
669                 locale = pointer.getLocale();
670             }
671             else {
672                 locale = context.getJXPathContext().getLocale();
673             }
674             symbols = new DecimalFormatSymbols JavaDoc(locale);
675         }
676         
677         DecimalFormat JavaDoc format = (DecimalFormat JavaDoc) NumberFormat.getInstance();
678         format.setDecimalFormatSymbols(symbols);
679         format.applyLocalizedPattern(pattern);
680         return format.format(number);
681     }
682
683     private void assertArgCount(int count) {
684         if (getArgumentCount() != count) {
685             throw new JXPathException("Incorrect number of argument: " + this);
686         }
687     }
688 }
Popular Tags