/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jxpath.ri.compiler; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import org.apache.commons.jxpath.Pointer; import org.apache.commons.jxpath.ri.EvalContext; import org.apache.commons.jxpath.ri.InfoSetUtil; import org.apache.commons.jxpath.ri.axes.InitialContext; import org.apache.commons.jxpath.ri.axes.SelfContext; /** * Common superclass for the implementations of Expression for the operations * "=" and "!=". * * @author Dmitri Plotnikov * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $ */ public abstract class CoreOperationCompare extends CoreOperation { private boolean invert; /** * Create a new CoreOperationCompare. * @param arg1 left operand * @param arg2 right operand */ public CoreOperationCompare(Expression arg1, Expression arg2) { this(arg1, arg2, false); } /** * Create a new CoreOperationCompare. * @param arg1 left operand * @param arg2 right operand * @param invert whether to invert (not) the comparison */ protected CoreOperationCompare(Expression arg1, Expression arg2, boolean invert) { super(new Expression[] { arg1, arg2 }); this.invert = invert; } public Object computeValue(EvalContext context) { return equal(context, args[0], args[1]) ? Boolean.TRUE : Boolean.FALSE; } protected int getPrecedence() { return COMPARE_PRECEDENCE; } protected boolean isSymmetric() { return true; } /** * Compares two values. * @param context evaluation context * @param left operand * @param right operand * @return whether left = right in XPath terms */ protected boolean equal(EvalContext context, Expression left, Expression right) { Object l = left.compute(context); Object r = right.compute(context); if (l instanceof InitialContext) { ((EvalContext) l).reset(); } if (l instanceof SelfContext) { l = ((EvalContext) l).getSingleNodePointer(); } if (r instanceof InitialContext) { ((EvalContext) r).reset(); } if (r instanceof SelfContext) { r = ((EvalContext) r).getSingleNodePointer(); } if (l instanceof Collection) { l = ((Collection) l).iterator(); } if (r instanceof Collection) { r = ((Collection) r).iterator(); } if (l instanceof Iterator && r instanceof Iterator) { return findMatch((Iterator) l, (Iterator) r); } if (l instanceof Iterator) { return contains((Iterator) l, r); } if (r instanceof Iterator) { return contains((Iterator) r, l); } return equal(l, r); } /** * Learn whether it contains value. * @param it Iterator to check * @param value for which to look * @return whether value was found */ protected boolean contains(Iterator it, Object value) { while (it.hasNext()) { Object element = it.next(); if (equal(element, value)) { return true; } } return false; } /** * Learn whether lit intersects rit. * @param lit left Iterator * @param rit right Iterator * @return boolean */ protected boolean findMatch(Iterator lit, Iterator rit) { HashSet left = new HashSet(); while (lit.hasNext()) { left.add(lit.next()); } while (rit.hasNext()) { if (contains(left.iterator(), rit.next())) { return true; } } return false; } /** * Learn whether l equals r in XPath terms. * @param l left operand * @param r right operand * @return whether l = r */ protected boolean equal(Object l, Object r) { if (l instanceof Pointer) { l = ((Pointer) l).getValue(); } if (r instanceof Pointer) { r = ((Pointer) r).getValue(); } boolean result; if (l instanceof Boolean || r instanceof Boolean) { result = l == r || InfoSetUtil.booleanValue(l) == InfoSetUtil.booleanValue(r); } else if (l instanceof Number || r instanceof Number) { //if either side is NaN, no comparison returns true: double ld = InfoSetUtil.doubleValue(l); if (Double.isNaN(ld)) { return false; } double rd = InfoSetUtil.doubleValue(r); if (Double.isNaN(rd)) { return false; } result = ld == rd; } else { if (l instanceof String || r instanceof String) { l = InfoSetUtil.stringValue(l); r = InfoSetUtil.stringValue(r); } result = l == r || l != null && l.equals(r); } return result ^ invert; } }