KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > xpath > Expr


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.xpath;
30
31 import com.caucho.util.CharBuffer;
32 import com.caucho.xml.XmlChar;
33 import com.caucho.xml.XmlUtil;
34 import com.caucho.xpath.expr.ObjectVar;
35 import com.caucho.xpath.expr.Var;
36 import com.caucho.xpath.pattern.AbstractPattern;
37 import com.caucho.xpath.pattern.FromExpr;
38 import com.caucho.xpath.pattern.NodeArrayListIterator;
39 import com.caucho.xpath.pattern.NodeIterator;
40 import com.caucho.xpath.pattern.NodeListIterator;
41 import com.caucho.xpath.pattern.SingleNodeIterator;
42
43 import org.w3c.dom.Node JavaDoc;
44 import org.w3c.dom.NodeList JavaDoc;
45
46 import java.util.ArrayList JavaDoc;
47 import java.util.Iterator JavaDoc;
48
49 /**
50  * Compute values from nodes. Because the expressions themselves are
51  * untyped, the class provides methods for creating the type of the
52  * desired result.
53  */

54 abstract public class Expr {
55   protected static final int CONST = 0;
56
57   protected static final int NODE_SET = CONST + 1;
58   protected static final int ID = NODE_SET + 1;
59
60   protected static final int OR = ID + 1;
61   protected static final int AND = OR + 1;
62
63   protected static final int EQ = AND + 1;
64   protected static final int NEQ = EQ + 1;
65   protected static final int LT = NEQ + 1;
66   protected static final int LE = LT + 1;
67   protected static final int GT = LE + 1;
68   protected static final int GE = GT + 1;
69   
70   protected static final int BOOLEAN_EQ = GE + 1;
71   protected static final int BOOLEAN_NEQ = BOOLEAN_EQ + 1;
72   
73   protected static final int NUMBER_EQ = BOOLEAN_NEQ + 1;
74   protected static final int NUMBER_NEQ = NUMBER_EQ + 1;
75   protected static final int NUMBER_LT = NUMBER_NEQ + 1;
76   protected static final int NUMBER_LE = NUMBER_LT + 1;
77   protected static final int NUMBER_GT = NUMBER_LE + 1;
78   protected static final int NUMBER_GE = NUMBER_GT + 1;
79   
80   protected static final int STRING_EQ = NUMBER_GE + 1;
81   protected static final int STRING_NEQ = STRING_EQ + 1;
82
83   protected static final int NEG = STRING_NEQ + 1;
84   protected static final int ADD = NEG + 1;
85   protected static final int SUB = ADD + 1;
86   protected static final int MUL = SUB + 1;
87   protected static final int DIV = MUL + 1;
88   protected static final int QUO = DIV + 1;
89   protected static final int MOD = QUO + 1;
90
91   protected static final int TRUE = MOD + 1;
92   protected static final int FALSE = TRUE + 1;
93   protected static final int NOT = FALSE + 1;
94   protected static final int BOOLEAN = NOT + 1;
95   protected static final int LANG = BOOLEAN + 1;
96
97   protected static final int NUMBER = LANG + 1;
98   protected static final int SUM = NUMBER + 1;
99   protected static final int FLOOR = SUM + 1;
100   protected static final int CEILING = FLOOR + 1;
101   protected static final int ROUND = CEILING + 1;
102   public static final int POSITION = ROUND + 1;
103   protected static final int COUNT = POSITION + 1;
104   protected static final int LAST = COUNT + 1;
105
106   protected static final int STRING = LAST + 1;
107   protected static final int CONCAT = STRING + 1;
108   protected static final int STARTS_WITH = CONCAT + 1;
109   protected static final int CONTAINS = STARTS_WITH + 1;
110   protected static final int SUBSTRING = CONTAINS + 1;
111   protected static final int SUBSTRING_BEFORE = SUBSTRING + 1;
112   protected static final int SUBSTRING_AFTER = SUBSTRING_BEFORE + 1;
113   protected static final int STRING_LENGTH = SUBSTRING_AFTER + 1;
114   protected static final int NORMALIZE = STRING_LENGTH + 1;
115   protected static final int TRANSLATE = NORMALIZE + 1;
116   protected static final int FORMAT_NUMBER = TRANSLATE + 1;
117
118   protected static final int LOCAL_PART = FORMAT_NUMBER + 1;
119   protected static final int NAMESPACE = LOCAL_PART + 1;
120   protected static final int QNAME = NAMESPACE + 1;
121   protected static final int GENERATE_ID = QNAME + 1;
122
123   protected static final int FUNCTION_AVAILABLE = GENERATE_ID + 1;
124   protected static final int SYSTEM_PROPERTY = FUNCTION_AVAILABLE + 1;
125
126   protected static final int IF = SYSTEM_PROPERTY + 1;
127   
128   protected static final int SELF = IF + 1;
129   protected static final int SELF_NAME = SELF + 1;
130   protected static final int ATTRIBUTE = SELF_NAME + 1;
131   protected static final int ELEMENT = ATTRIBUTE + 1;
132   
133   protected static final int BASE_URI = ELEMENT + 1;
134   protected static final int LAST_FUN = BASE_URI + 1;
135
136   private AbstractPattern listContext;
137   
138   protected Expr() {}
139
140   public void setListContext(AbstractPattern listContext)
141   {
142     this.listContext = listContext;
143   }
144
145   public AbstractPattern getListContext()
146   {
147     return listContext;
148   }
149   
150   /**
151    * true if the expression prefers to return a number.
152    */

153   public boolean isNumber()
154   {
155     return false;
156   }
157   
158   /**
159    * Evaluates the expression as a double using the node as a context.
160    *
161    * @param node the node to evaluate and use as a context
162    *
163    * @return the numeric value.
164    */

165   public double evalNumber(Node JavaDoc node)
166     throws XPathException
167   {
168     Env env = XPath.createEnv();
169     env.setCurrentNode(node);
170     env.setContextNode(node);
171
172     double result = evalNumber(node, env);
173
174     XPath.freeEnv(env);
175
176     return result;
177   }
178
179   /**
180    * Evaluates the expression as a number.
181    *
182    * @param node the current node.
183    * @param env variable environment.
184    *
185    * @return the numeric value.
186    */

187   public abstract double evalNumber(Node JavaDoc node, ExprEnvironment env)
188     throws XPathException;
189
190   /**
191    * true if the expression prefers to return a boolean.
192    */

193   public boolean isBoolean()
194   {
195     return false;
196   }
197
198   /**
199    * Returns the boolean value of the node.
200    *
201    * @param node the node to evaluate and use as a context
202    *
203    * @return the boolean value
204    */

205   public boolean evalBoolean(Node JavaDoc node)
206     throws XPathException
207   {
208     Env env = XPath.createEnv();
209     env.setCurrentNode(node);
210     env.setContextNode(node);
211
212     boolean result = evalBoolean(node, env);
213
214     XPath.freeEnv(env);
215
216     return result;
217   }
218
219   /**
220    * Returns the boolean value of the node.
221    *
222    * @param node the node to evaluate and use as a context
223    * @param env variable environment.
224    *
225    * @return the boolean value.
226    */

227   public abstract boolean evalBoolean(Node JavaDoc node, ExprEnvironment env)
228     throws XPathException;
229
230   /**
231    * Returns the expression evaluated as a string.
232    *
233    * @param node the node to evaluate and use as a context
234    *
235    * @return the string value of the expression.
236    */

237   public String JavaDoc evalString(Node JavaDoc node)
238     throws XPathException
239   {
240     Env env = XPath.createEnv();
241     env.setCurrentNode(node);
242     env.setContextNode(node);
243
244     String JavaDoc result = evalString(node, env);
245
246     XPath.freeEnv(env);
247
248     return result;
249   }
250
251   /**
252    * true if the expression prefers to return a string.
253    */

254   public boolean isString()
255   {
256     return false;
257   }
258
259   /**
260    * Returns the string value of the node.
261    *
262    * @param node the node to evaluate and use as a context
263    * @param env variable environment.
264    */

265   public abstract String JavaDoc evalString(Node JavaDoc node, ExprEnvironment env)
266     throws XPathException;
267   
268   /**
269    * Fills a char buffer with the evaluated string results.
270    *
271    * @param cb the buffer containing the results.
272    * @param node the node to evaluate and use as a context
273    */

274   public void evalString(CharBuffer cb, Node JavaDoc node)
275     throws XPathException
276   {
277     Env env = XPath.createEnv();
278     env.setCurrentNode(node);
279     env.setContextNode(node);
280
281     evalString(cb, node, env);
282
283     XPath.freeEnv(env);
284   }
285   
286   /**
287    * Fills a char buffer with the evaluated string results.
288    *
289    * @param cb the buffer containing the results.
290    * @param node the node to evaluate and use as a context
291    * @param env the variable environment
292    */

293   public void evalString(CharBuffer cb, Node JavaDoc node, ExprEnvironment env)
294     throws XPathException
295   {
296     cb.append(evalString(node, env));
297   }
298
299   /**
300    * true if the expression prefers to return a node set.
301    */

302   public boolean isNodeSet()
303   {
304     return false;
305   }
306
307   /**
308    * Returns an iterator of matching nodes
309    *
310    * @param node the node to evaluate and use as a context
311    *
312    * @return the value as a node iterator.
313    */

314   public NodeIterator evalNodeSet(Node JavaDoc node)
315     throws XPathException
316   {
317     Env env = XPath.createEnv();
318     env.setCurrentNode(node);
319     env.setContextNode(node);
320
321     NodeIterator result = evalNodeSet(node, env);
322
323     XPath.freeEnv(env);
324
325     return result;
326   }
327
328   /**
329    * Returns an iterator of matching nodes
330    *
331    * @param node the node to evaluate and use as a context
332    * @param env variable environment.
333    *
334    * @return the value as a node iterator.
335    */

336   public NodeIterator evalNodeSet(Node JavaDoc node, ExprEnvironment env)
337     throws XPathException
338   {
339     Object JavaDoc obj = evalObject(node, env);
340
341     if (obj instanceof Node JavaDoc)
342       return new SingleNodeIterator(env, (Node JavaDoc) obj);
343
344     else if (obj instanceof NodeList JavaDoc)
345       return new NodeListIterator(env, (NodeList JavaDoc) obj);
346
347     else if (obj instanceof NodeIterator)
348       return (NodeIterator) obj;
349
350     else if (obj instanceof ArrayList JavaDoc)
351       return new NodeArrayListIterator(env, (ArrayList JavaDoc) obj);
352
353     else {
354       return new SingleNodeIterator(env, null);
355     }
356   }
357   
358   /**
359    * Returns the object value of the node.
360    *
361    * @param node the node to evaluate and use as a context
362    */

363   public Object JavaDoc evalObject(Node JavaDoc node)
364     throws XPathException
365   {
366     Env env = XPath.createEnv();
367     env.setCurrentNode(node);
368     env.setContextNode(node);
369
370     Object JavaDoc result = evalObject(node, env);
371
372     XPath.freeEnv(env);
373
374     return result;
375   }
376
377   /**
378    * Returns the object value of the node.
379    *
380    * @param node the node to evaluate and use as a context
381    * @param env variable environment.
382    */

383   public abstract Object JavaDoc evalObject(Node JavaDoc node, ExprEnvironment env)
384     throws XPathException;
385
386   /**
387    * Evaluates to a variable.
388    *
389    * @param node the node to evaluate and use as a context.
390    * @param env the variable environment.
391    *
392    * @return a variable containing the value.
393    */

394   public Var evalVar(Node JavaDoc node, ExprEnvironment env)
395     throws XPathException
396   {
397     Object JavaDoc obj = evalObject(node, env);
398
399     return new ObjectVar(obj);
400   }
401
402   /**
403    * Adds a variable with the expression's value.
404    */

405   public void addVar(Env newEnv, String JavaDoc name, Node JavaDoc node, Env env)
406     throws XPathException
407   {
408     Var var = evalVar(node, env);
409
410     newEnv.addVar(name, var);
411   }
412
413   /**
414    * Sets a variable with the expression's value.
415    */

416   public void setVar(String JavaDoc name, Node JavaDoc node, Env env)
417     throws XPathException
418   {
419     env.setVar(name, evalVar(node, env));
420   }
421
422   /**
423    * Adds a param with the expression's value.
424    */

425   public void addParam(Env newEnv, String JavaDoc name,
426                        Node JavaDoc node, Env env)
427     throws XPathException
428   {
429     Var var = env.getVar(name);
430       
431     if (var == null)
432       newEnv.addVar(name, evalVar(node, env));
433     else
434       newEnv.addVar(name, var);
435   }
436
437   /**
438    * Convert a Java object to a boolean using the XPath rules.
439    */

440   public static boolean toBoolean(Object JavaDoc value)
441     throws XPathException
442   {
443     if (value instanceof Node JavaDoc)
444       value = XmlUtil.textValue((Node JavaDoc) value);
445     else if (value instanceof NodeList JavaDoc) {
446       NodeList JavaDoc list = (NodeList JavaDoc) value;
447
448       return list.item(0) != null;
449     }
450     else if (value instanceof ArrayList JavaDoc) {
451       ArrayList JavaDoc list = (ArrayList JavaDoc) value;
452       return list.size() > 0;
453     }
454     else if (value instanceof Iterator) {
455       return ((Iterator) value).hasNext();
456     }
457
458     if (value == null)
459       return false;
460
461     else if (value instanceof Double JavaDoc) {
462       Double JavaDoc d = (Double JavaDoc) value;
463
464       return d.doubleValue() != 0;
465     }
466     else if (value instanceof Boolean JavaDoc) {
467       Boolean JavaDoc b = (Boolean JavaDoc) value;
468       return b.booleanValue();
469     }
470     else if (value instanceof String JavaDoc) {
471       String JavaDoc string = (String JavaDoc) value;
472       return string != null && string.length() > 0;
473     }
474     else
475       return true;
476   }
477
478   /**
479    * Convert a Java object to a double using the XPath rules.
480    */

481   public static double toDouble(Object JavaDoc value)
482     throws XPathException
483   {
484     if (value instanceof Node JavaDoc) {
485       String JavaDoc string = XmlUtil.textValue((Node JavaDoc) value);
486
487       if (string == null)
488     return 0;
489       else
490     return stringToNumber(string);
491     }
492     else if (value instanceof NodeList JavaDoc) {
493       NodeList JavaDoc list = (NodeList JavaDoc) value;
494
495       value = list.item(0);
496     }
497     else if (value instanceof ArrayList JavaDoc) {
498       ArrayList JavaDoc list = (ArrayList JavaDoc) value;
499       if (list.size() > 0)
500     value = list.get(0);
501       else
502     value = null;
503     }
504     else if (value instanceof NodeIterator) {
505       value = ((NodeIterator) value).nextNode();
506     }
507
508     if (value instanceof Node JavaDoc)
509       value = XmlUtil.textValue((Node JavaDoc) value);
510
511     if (value == null)
512       return 0;
513
514     if (value instanceof Number JavaDoc) {
515       Number JavaDoc d = (Number JavaDoc) value;
516
517       return d.doubleValue();
518     }
519     else if (value instanceof Boolean JavaDoc) {
520       Boolean JavaDoc b = (Boolean JavaDoc) value;
521       return b.booleanValue() ? 1 : 0;
522     }
523     else if (value instanceof String JavaDoc) {
524       return stringToNumber((String JavaDoc) value);
525     }
526     else
527       return 0;
528   }
529
530   /**
531    * Convert a Java object to a string using the XPath rules.
532    */

533   public static String JavaDoc toString(Object JavaDoc value)
534     throws XPathException
535   {
536     if (value instanceof Node JavaDoc) {
537       String JavaDoc s = XmlUtil.textValue((Node JavaDoc) value);
538
539       if (s == null)
540     return "";
541       else
542     return s;
543     }
544     else if (value instanceof NodeList JavaDoc) {
545       NodeList JavaDoc list = (NodeList JavaDoc) value;
546
547       value = list.item(0);
548     }
549     else if (value instanceof ArrayList JavaDoc) {
550       ArrayList JavaDoc list = (ArrayList JavaDoc) value;
551       if (list.size() > 0)
552     value = list.get(0);
553       else
554     value = null;
555     }
556     else if (value instanceof Iterator) {
557       value = ((Iterator) value).next();
558     }
559
560     if (value instanceof Node JavaDoc)
561       value = XmlUtil.textValue((Node JavaDoc) value);
562     else if (value instanceof Double JavaDoc) {
563       double d = ((Double JavaDoc) value).doubleValue();
564
565       if ((int) d == d)
566     return String.valueOf((int) d);
567       else
568     return String.valueOf(d);
569     }
570
571     if (value == null)
572       return "";
573     else
574       return value.toString();
575   }
576
577   /**
578    * Convert a Java object to a node using the XPath rules.
579    */

580   public static Node JavaDoc toNode(Object JavaDoc value)
581     throws XPathException
582   {
583     if (value instanceof Node JavaDoc)
584       return (Node JavaDoc) value;
585     else if (value instanceof NodeList JavaDoc) {
586       NodeList JavaDoc list = (NodeList JavaDoc) value;
587       value = list.item(0);
588     }
589     else if (value instanceof ArrayList JavaDoc) {
590       ArrayList JavaDoc list = (ArrayList JavaDoc) value;
591       if (list.size() > 0)
592     value = list.get(0);
593       else
594     value = null;
595     }
596     else if (value instanceof NodeIterator) {
597       value = ((NodeIterator) value).nextNode();
598     }
599
600     if (value instanceof Node JavaDoc)
601       return (Node JavaDoc) value;
602     else
603       return null;
604   }
605
606   /**
607    * Convert a string to a double following XPath.
608    *
609    * @param string string to be treated as a double.
610    * @return the double value.
611    */

612   static protected double stringToNumber(String JavaDoc string)
613     throws XPathException
614   {
615     int i = 0;
616     int length = string.length();
617     boolean isNumber = false;
618     for (; i < length && XmlChar.isWhitespace(string.charAt(i)); i++) {
619     }
620
621     if (i >= length)
622       return 0;
623
624     int ch = string.charAt(i);;
625     int sign = 1;
626     if (ch == '-') {
627       sign = -1;
628       for (i++; i < length && XmlChar.isWhitespace(string.charAt(i)); i++) {
629       }
630     }
631       
632     double value = 0;
633     double exp = 1;
634     for (; i < length && (ch = string.charAt(i)) >= '0' && ch <= '9'; i++) {
635       value = 10 * value + ch - '0';
636       isNumber = true;
637     }
638
639     if (ch == '.') {
640       for (i++;
641        i < length && (ch = string.charAt(i)) >= '0' && ch <= '9';
642        i++) {
643     value = 10 * value + ch - '0';
644     isNumber = true;
645     exp = 10 * exp;
646       }
647     }
648
649     double pexp = 1.0;
650     if (ch == 'e' || ch == 'E') {
651       int eSign = 1;
652       i++;
653
654       if (i >= length)
655         return Double.NaN;
656
657       if (string.charAt(i) == '-') {
658         eSign = -1;
659         i++;
660       }
661       else if (string.charAt(i) == '+') {
662         i++;
663       }
664
665       int v = 0;
666       for (; i < length && (ch = string.charAt(i)) >= '0' && ch <= '9'; i++) {
667         v = v * 10 + ch - '0';
668       }
669
670       pexp = Math.pow(10, eSign * v);
671     }
672
673     for (; i < length && XmlChar.isWhitespace(string.charAt(i)); i++) {
674     }
675
676     if (i < length || ! isNumber)
677       return Double.NaN;
678     else
679       return sign * value * pexp / exp;
680   }
681
682   /**
683    * Convert from an expression to a pattern.
684    */

685   protected AbstractPattern toNodeList()
686   {
687     return new FromExpr(null, this);
688   }
689 }
690
Popular Tags