001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.Item;
004: import net.sf.saxon.om.NodeInfo;
005: import net.sf.saxon.sort.GlobalOrderComparer;
006: import net.sf.saxon.trans.XPathException;
007: import net.sf.saxon.type.ItemType;
008: import net.sf.saxon.type.Type;
009: import net.sf.saxon.type.TypeHierarchy;
010: import net.sf.saxon.value.BooleanValue;
011: import net.sf.saxon.value.SequenceType;
012:
013: /**
014: * IdentityComparison: a boolean expression that compares two nodes
015: * for equals, not-equals, greater-than or less-than based on identity and
016: * document ordering
017: */
018:
019: public final class IdentityComparison extends BinaryExpression {
020:
021: private boolean generateIdEmulation = false;
022:
023: // this flag is set if an "X is Y" or "X isnot Y" comparison is being used
024: // to emulate generate-id(X) = / != generate-id(Y). The handling of an empty
025: // sequence in the two cases is different.
026:
027: /**
028: * Create an identity comparison identifying the two operands and the operator
029: * @param p1 the left-hand operand
030: * @param op the operator, as a token returned by the Tokenizer (e.g. Token.LT)
031: * @param p2 the right-hand operand
032: */
033:
034: public IdentityComparison(Expression p1, int op, Expression p2) {
035: super (p1, op, p2);
036: }
037:
038: /**
039: * Set flag to indicate different empty-sequence behavior when emulating
040: * comparison of two generate-id's
041: */
042:
043: public void setGenerateIdEmulation(boolean flag) {
044: generateIdEmulation = flag;
045: }
046:
047: /**
048: * Type-check the expression
049: */
050:
051: public Expression typeCheck(StaticContext env,
052: ItemType contextItemType) throws XPathException {
053:
054: operand0 = operand0.typeCheck(env, contextItemType);
055: operand1 = operand1.typeCheck(env, contextItemType);
056:
057: RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR,
058: Token.tokens[operator], 0, null);
059: role0.setSourceLocator(this );
060: operand0 = TypeChecker.staticTypeCheck(operand0,
061: SequenceType.OPTIONAL_NODE, false, role0, env);
062:
063: RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR,
064: Token.tokens[operator], 1, null);
065: role1.setSourceLocator(this );
066: operand1 = TypeChecker.staticTypeCheck(operand1,
067: SequenceType.OPTIONAL_NODE, false, role1, env);
068: return this ;
069: }
070:
071: /**
072: * Evaluate the expression
073: */
074:
075: public Item evaluateItem(XPathContext context)
076: throws XPathException {
077: NodeInfo node1 = getNode(operand0, context);
078: if (node1 == null) {
079: if (generateIdEmulation) {
080: return BooleanValue
081: .get(getNode(operand1, context) == null);
082: }
083: return null;
084: }
085:
086: NodeInfo node2 = getNode(operand1, context);
087: if (node2 == null) {
088: if (generateIdEmulation) {
089: return BooleanValue.FALSE;
090: }
091: return null;
092: }
093:
094: return BooleanValue.get(compareIdentity(node1, node2));
095: }
096:
097: public boolean effectiveBooleanValue(XPathContext context)
098: throws XPathException {
099: NodeInfo node1 = getNode(operand0, context);
100: if (node1 == null) {
101: if (generateIdEmulation) {
102: return getNode(operand1, context) == null;
103: }
104: return false;
105: }
106:
107: NodeInfo node2 = getNode(operand1, context);
108: if (node2 == null)
109: return false;
110:
111: return compareIdentity(node1, node2);
112: }
113:
114: private boolean compareIdentity(NodeInfo node1, NodeInfo node2) {
115:
116: switch (operator) {
117: case Token.IS:
118: return node1.isSameNodeInfo(node2);
119: // case Token.ISNOT:
120: // return !node1.isSameNode(node2);
121: case Token.PRECEDES:
122: return GlobalOrderComparer.getInstance().compare(node1,
123: node2) < 0;
124: case Token.FOLLOWS:
125: return GlobalOrderComparer.getInstance().compare(node1,
126: node2) > 0;
127: default:
128: throw new UnsupportedOperationException(
129: "Unknown node identity test");
130: }
131: }
132:
133: private NodeInfo getNode(Expression exp, XPathContext c)
134: throws XPathException {
135: return (NodeInfo) exp.evaluateItem(c);
136: }
137:
138: /**
139: * Determine the data type of the expression
140: * @return Type.BOOLEAN
141: * @param th
142: */
143:
144: public ItemType getItemType(TypeHierarchy th) {
145: return Type.BOOLEAN_TYPE;
146: }
147:
148: }
149:
150: //
151: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
152: // you may not use this file except in compliance with the License. You may obtain a copy of the
153: // License at http://www.mozilla.org/MPL/
154: //
155: // Software distributed under the License is distributed on an "AS IS" basis,
156: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
157: // See the License for the specific language governing rights and limitations under the License.
158: //
159: // The Original Code is: all this file.
160: //
161: // The Initial Developer of the Original Code is Michael H. Kay
162: //
163: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
164: //
165: // Contributor(s): none.
166: //
|