001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.xpath.expr;
030:
031: import com.caucho.xpath.Expr;
032: import com.caucho.xpath.ExprEnvironment;
033: import com.caucho.xpath.XPathException;
034: import com.caucho.xpath.pattern.NodeIterator;
035:
036: import org.w3c.dom.Element;
037: import org.w3c.dom.Node;
038: import org.w3c.dom.NodeList;
039:
040: import java.util.ArrayList;
041: import java.util.Iterator;
042:
043: public class BooleanExpr extends Expr {
044: private int _code;
045: private Expr _left;
046: private Expr _right;
047: private boolean _value;
048: private ArrayList _args;
049:
050: public BooleanExpr(int code, Expr left, Expr right) {
051: _code = code;
052: _left = left;
053: _right = right;
054:
055: if (code == Expr.EQ) {
056: if (_left.isNodeSet() || _right.isNodeSet())
057: _code = Expr.EQ;
058: else if (_left.isBoolean() || _right.isBoolean())
059: _code = Expr.BOOLEAN_EQ;
060: else if (left.isNumber() || right.isNumber())
061: _code = Expr.NUMBER_EQ;
062: else if (left.isString() && right.isString())
063: _code = Expr.STRING_EQ;
064: else
065: _code = Expr.EQ;
066: } else if (code == Expr.NEQ) {
067: if (left.isNodeSet() || right.isNodeSet())
068: _code = Expr.NEQ;
069: else if (left.isBoolean() || right.isBoolean())
070: _code = Expr.BOOLEAN_NEQ;
071: else if (left.isNumber() || right.isNumber())
072: _code = Expr.NUMBER_NEQ;
073: else if (left.isString() && right.isString())
074: _code = Expr.STRING_NEQ;
075: else
076: _code = Expr.NEQ;
077: } else if (code == Expr.LT) {
078: if (left.isNodeSet() || right.isNodeSet())
079: _code = Expr.LT;
080: else if (left.isNumber() || right.isNumber())
081: _code = Expr.NUMBER_LT;
082: else
083: _code = Expr.LT;
084: } else if (code == Expr.LE) {
085: if (left.isNodeSet() || right.isNodeSet())
086: _code = Expr.LE;
087: else if (left.isNumber() || right.isNumber())
088: _code = Expr.NUMBER_LE;
089: else
090: _code = Expr.LE;
091: } else if (code == Expr.GT) {
092: if (left.isNodeSet() || right.isNodeSet())
093: _code = Expr.GT;
094: else if (left.isNumber() || right.isNumber())
095: _code = Expr.NUMBER_GT;
096: else
097: _code = Expr.GT;
098: } else if (code == Expr.GE) {
099: if (left.isNodeSet() || right.isNodeSet())
100: _code = Expr.GE;
101: else if (left.isNumber() || right.isNumber())
102: _code = Expr.NUMBER_GE;
103: else
104: _code = Expr.GE;
105: }
106: }
107:
108: public BooleanExpr(int code, Expr expr) {
109: _code = code;
110: _left = expr;
111: }
112:
113: public BooleanExpr(boolean value) {
114: _code = CONST;
115: _value = value;
116: }
117:
118: public BooleanExpr(int code, ArrayList args) {
119: _code = code;
120: _args = args;
121:
122: if (args.size() > 0)
123: _left = (Expr) args.get(0);
124: if (args.size() > 1)
125: _right = (Expr) args.get(1);
126: }
127:
128: public boolean isBoolean() {
129: return true;
130: }
131:
132: /**
133: * Evaluates the expression as a boolean.
134: *
135: * @param node current node
136: * @param env the environment
137: *
138: * @return the boolean representation
139: */
140: public boolean evalBoolean(Node node, ExprEnvironment env)
141: throws XPathException {
142: switch (_code) {
143: case CONST:
144: return _value;
145:
146: case BOOLEAN_EQ:
147: return (_left.evalBoolean(node, env) == _right.evalBoolean(
148: node, env));
149:
150: case NUMBER_EQ:
151: return (_left.evalNumber(node, env) == _right.evalNumber(
152: node, env));
153:
154: case STRING_EQ:
155: String lstr = _left.evalString(node, env);
156: String rstr = _right.evalString(node, env);
157:
158: return lstr.equals(rstr);
159:
160: case EQ:
161: Object lobj = _left.evalObject(node, env);
162: Object robj = _right.evalObject(node, env);
163:
164: if (lobj == robj)
165: return true;
166:
167: return cmp(P_EQ, lobj, robj);
168:
169: case BOOLEAN_NEQ:
170: return (_left.evalBoolean(node, env) != _right.evalBoolean(
171: node, env));
172:
173: case NUMBER_NEQ:
174: return (_left.evalNumber(node, env) != _right.evalNumber(
175: node, env));
176:
177: case STRING_NEQ:
178: lstr = _left.evalString(node, env);
179: rstr = _right.evalString(node, env);
180: return !lstr.equals(rstr);
181:
182: case NEQ:
183: lobj = _left.evalObject(node, env);
184: robj = _right.evalObject(node, env);
185:
186: if (lobj == robj)
187: return false;
188:
189: return cmp(P_NEQ, lobj, robj);
190:
191: case LT:
192: return cmp(P_LT, _left.evalObject(node, env), _right
193: .evalObject(node, env));
194:
195: case LE:
196: return cmp(P_LE, _left.evalObject(node, env), _right
197: .evalObject(node, env));
198:
199: case GT:
200: return cmp(P_GT, _left.evalObject(node, env), _right
201: .evalObject(node, env));
202:
203: case GE:
204: return cmp(P_GE, _left.evalObject(node, env), _right
205: .evalObject(node, env));
206:
207: case NUMBER_LT:
208: return (_left.evalNumber(node, env) < _right.evalNumber(
209: node, env));
210:
211: case NUMBER_LE:
212: return (_left.evalNumber(node, env) <= _right.evalNumber(
213: node, env));
214:
215: case NUMBER_GT:
216: return (_left.evalNumber(node, env) > _right.evalNumber(
217: node, env));
218:
219: case NUMBER_GE:
220: return (_left.evalNumber(node, env) >= _right.evalNumber(
221: node, env));
222:
223: case OR:
224: return (_left.evalBoolean(node, env) || _right.evalBoolean(
225: node, env));
226:
227: case AND:
228: return (_left.evalBoolean(node, env) && _right.evalBoolean(
229: node, env));
230:
231: case TRUE:
232: return true;
233:
234: case FALSE:
235: return false;
236:
237: case NOT:
238: return !_left.evalBoolean(node, env);
239:
240: case BOOLEAN:
241: return _left.evalBoolean(node, env);
242:
243: case STARTS_WITH:
244: lstr = _left.evalString(node, env);
245: rstr = _right.evalString(node, env);
246: return lstr.startsWith(rstr);
247:
248: case CONTAINS:
249: lstr = _left.evalString(node, env);
250: rstr = _right.evalString(node, env);
251: return lstr.indexOf(rstr) >= 0;
252:
253: case LANG:
254: lstr = _left.evalString(node, env);
255: for (; node != null; node = node.getParentNode()) {
256: if (!(node instanceof Element))
257: continue;
258: String lang = ((Element) node).getAttribute("xml:lang");
259: if (lang != null && lang.equals(lstr))
260: return true;
261: }
262: return false;
263:
264: case FUNCTION_AVAILABLE:
265: return false;
266:
267: default:
268: throw new RuntimeException("unknown code: " + _code);
269: }
270: }
271:
272: private boolean cmp(Predicate test, Object lobj, Object robj)
273: throws XPathException {
274: if (lobj instanceof Node) {
275: } else if (lobj instanceof NodeList) {
276: NodeList list = (NodeList) lobj;
277:
278: int length = list.getLength();
279:
280: for (int i = 0; i < length; i++) {
281: if (cmp(test, list.item(i), robj))
282: return true;
283: }
284:
285: return false;
286: } else if (lobj instanceof ArrayList) {
287: ArrayList list = (ArrayList) lobj;
288:
289: for (int i = 0; i < list.size(); i++) {
290: if (cmp(test, list.get(i), robj))
291: return true;
292: }
293:
294: return false;
295: } else if (lobj instanceof Iterator) {
296: Iterator iter = (Iterator) lobj;
297:
298: while (iter.hasNext()) {
299: if (cmp(test, iter.next(), robj))
300: return true;
301: }
302:
303: return false;
304: }
305:
306: if (robj instanceof Node) {
307: } else if (robj instanceof NodeList) {
308: NodeList list = (NodeList) robj;
309:
310: int length = list.getLength();
311: for (int i = 0; i < length; i++) {
312: if (cmp(test, lobj, list.item(i)))
313: return true;
314: }
315:
316: return false;
317: } else if (robj instanceof ArrayList) {
318: ArrayList list = (ArrayList) robj;
319:
320: for (int i = 0; i < list.size(); i++) {
321: if (cmp(test, lobj, list.get(i)))
322: return true;
323: }
324:
325: return false;
326: } else if (robj instanceof NodeIterator) {
327: Iterator iter = null;
328:
329: iter = (Iterator) ((NodeIterator) robj).clone();
330:
331: while (iter.hasNext()) {
332: if (cmp(test, lobj, iter.next()))
333: return true;
334: }
335: return false;
336: }
337:
338: return test.test(lobj, robj);
339: }
340:
341: /**
342: * Evaluates the expression as a number.
343: *
344: * @param node current node
345: * @param env the environment
346: *
347: * @return the numeric representation
348: */
349: public double evalNumber(Node node, ExprEnvironment env)
350: throws XPathException {
351: if (evalBoolean(node, env))
352: return 1.0;
353: else
354: return 0.0;
355: }
356:
357: /**
358: * Evaluates the expression as a string.
359: *
360: * @param node current node
361: * @param env the environment
362: *
363: * @return the string representation
364: */
365: public String evalString(Node node, ExprEnvironment env)
366: throws XPathException {
367: if (evalBoolean(node, env))
368: return "true";
369: else
370: return "false";
371: }
372:
373: /**
374: * Evaluates the expression as a object.
375: *
376: * @param node current node
377: * @param env the environment
378: *
379: * @return the object representation
380: */
381: public Object evalObject(Node node, ExprEnvironment env)
382: throws XPathException {
383: return new Boolean(evalBoolean(node, env));
384: }
385:
386: public String toString() {
387: switch (_code) {
388: case CONST:
389: return String.valueOf(_value);
390:
391: case BOOLEAN_EQ:
392: case NUMBER_EQ:
393: case STRING_EQ:
394: case EQ:
395: return "(" + _left.toString() + " = " + _right.toString()
396: + ")";
397:
398: case BOOLEAN_NEQ:
399: case NUMBER_NEQ:
400: case STRING_NEQ:
401: case NEQ:
402: return "(" + _left.toString() + " != " + _right.toString()
403: + ")";
404:
405: case LT:
406: case NUMBER_LT:
407: return "(" + _left.toString() + " < " + _right.toString()
408: + ")";
409:
410: case LE:
411: case NUMBER_LE:
412: return "(" + _left.toString() + " <= " + _right.toString()
413: + ")";
414:
415: case GT:
416: case NUMBER_GT:
417: return "(" + _left.toString() + " > " + _right.toString()
418: + ")";
419:
420: case GE:
421: case NUMBER_GE:
422: return "(" + _left.toString() + " >= " + _right.toString()
423: + ")";
424:
425: case OR:
426: return "(" + _left.toString() + " or " + _right.toString()
427: + ")";
428:
429: case AND:
430: return "(" + _left.toString() + " and " + _right.toString()
431: + ")";
432:
433: case TRUE:
434: return "true()";
435:
436: case FALSE:
437: return "false()";
438:
439: case NOT:
440: return "not(" + _left.toString() + ")";
441:
442: case BOOLEAN:
443: return "boolean(" + _left.toString() + ")";
444:
445: case STARTS_WITH:
446: return "starts-with(" + _left + ", " + _right + ")";
447:
448: case CONTAINS:
449: return "contains(" + _left + ", " + _right + ")";
450:
451: case LANG:
452: return "lang(" + _left + ")";
453:
454: case FUNCTION_AVAILABLE:
455: return "function-available(" + _left + ")";
456:
457: default:
458: return super .toString();
459: }
460: }
461:
462: abstract static class Predicate {
463: abstract public boolean test(Object l, Object r)
464: throws XPathException;
465: }
466:
467: final static Predicate P_EQ = new Predicate() {
468: public boolean test(Object lobj, Object robj)
469: throws XPathException {
470: if (lobj instanceof Boolean || robj instanceof Boolean)
471: return toBoolean(lobj) == toBoolean(robj);
472: else if (lobj instanceof Double || robj instanceof Double)
473: return toDouble(lobj) == toDouble(robj);
474: else
475: return BooleanExpr.toString(lobj).equals(
476: BooleanExpr.toString(robj));
477: }
478: };
479:
480: final static Predicate P_NEQ = new Predicate() {
481: public boolean test(Object lobj, Object robj)
482: throws XPathException {
483: if (lobj instanceof Boolean || robj instanceof Boolean)
484: return toBoolean(lobj) != toBoolean(robj);
485: else if (lobj instanceof Double || robj instanceof Double)
486: return toDouble(lobj) != toDouble(robj);
487: else
488: return !BooleanExpr.toString(lobj).equals(
489: BooleanExpr.toString(robj));
490: }
491: };
492:
493: final static Predicate P_LT = new Predicate() {
494: public boolean test(Object lobj, Object robj)
495: throws XPathException {
496: return toDouble(lobj) < toDouble(robj);
497: }
498: };
499:
500: final static Predicate P_LE = new Predicate() {
501: public boolean test(Object lobj, Object robj)
502: throws XPathException {
503: return toDouble(lobj) <= toDouble(robj);
504: }
505: };
506:
507: final static Predicate P_GT = new Predicate() {
508: public boolean test(Object lobj, Object robj)
509: throws XPathException {
510: return toDouble(lobj) > toDouble(robj);
511: }
512: };
513:
514: final static Predicate P_GE = new Predicate() {
515: public boolean test(Object lobj, Object robj)
516: throws XPathException {
517: return toDouble(lobj) >= toDouble(robj);
518: }
519: };
520: }
|