EqualityExpr.java 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /* EqualityExpr.java --
  2. Copyright (C) 2004 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package gnu.xml.xpath;
  32. import java.util.Collection;
  33. import java.util.Iterator;
  34. import javax.xml.namespace.QName;
  35. import org.w3c.dom.Node;
  36. /**
  37. * Boolean equality expression.
  38. *
  39. * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  40. */
  41. final class EqualityExpr
  42. extends Expr
  43. {
  44. final Expr lhs;
  45. final Expr rhs;
  46. final boolean invert;
  47. EqualityExpr(Expr lhs, Expr rhs, boolean invert)
  48. {
  49. this.lhs = lhs;
  50. this.rhs = rhs;
  51. this.invert = invert;
  52. }
  53. @Override
  54. public Object evaluate(Node context, int pos, int len)
  55. {
  56. boolean val = evaluateImpl(context, pos, len);
  57. if (invert)
  58. {
  59. return val ? Boolean.FALSE : Boolean.TRUE;
  60. }
  61. else
  62. {
  63. return val ? Boolean.TRUE : Boolean.FALSE;
  64. }
  65. }
  66. private boolean evaluateImpl(Node context, int pos, int len)
  67. {
  68. Object left = lhs.evaluate(context, pos, len);
  69. Object right = rhs.evaluate(context, pos, len);
  70. /*
  71. * If both objects to be compared are node-sets, then the comparison
  72. * will be true if and only if there is a node in the first node-set and
  73. * a node in the second node-set such that the result of performing the
  74. * comparison on the string-values of the two nodes is true.
  75. */
  76. boolean flns = left instanceof Collection;
  77. boolean frns = right instanceof Collection;
  78. if (flns && frns)
  79. {
  80. /* Suppression is safe, as we know context produces Collection<Node> */
  81. @SuppressWarnings("unchecked")
  82. Collection<Node> lns = (Collection<Node>) left;
  83. @SuppressWarnings("unchecked")
  84. Collection<Node> rns = (Collection<Node>) right;
  85. if (lns.isEmpty())
  86. {
  87. return false;
  88. }
  89. boolean all = true;
  90. for (Node ltest : lns)
  91. {
  92. for (Node rtest : rns)
  93. {
  94. if (ltest == rtest || ltest.equals(rtest))
  95. {
  96. // much shorter
  97. if (!invert)
  98. {
  99. return true;
  100. }
  101. }
  102. else if (stringValue(ltest).equals(stringValue(rtest)))
  103. {
  104. if (!invert)
  105. {
  106. return true;
  107. }
  108. }
  109. else
  110. {
  111. all = false;
  112. }
  113. }
  114. }
  115. return all;
  116. }
  117. /*
  118. * If one object to be compared is a node-set and the other is a number,
  119. * then the comparison will be true if and only if there is a node in
  120. * the node-set such that the result of performing the comparison on the
  121. * number to be compared and on the result of converting the
  122. * string-value of that node to a number using the number function is
  123. * true.
  124. */
  125. boolean fln = left instanceof Double;
  126. boolean frn = right instanceof Double;
  127. if ((flns && frn) || (frns && fln))
  128. {
  129. /* Suppression is safe, as we know context produces Collection<Node> */
  130. @SuppressWarnings("unchecked")
  131. Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
  132. double n = fln ? ((Double) left).doubleValue() :
  133. ((Double) right).doubleValue();
  134. boolean all = true;
  135. for (Node test : ns)
  136. {
  137. double nn = _number(context, stringValue(test));
  138. if (nn == n)
  139. {
  140. if (!invert)
  141. {
  142. return true;
  143. }
  144. }
  145. else
  146. {
  147. all = false;
  148. }
  149. }
  150. return invert ? all : false;
  151. }
  152. /*
  153. * If one object to be compared is a node-set and the other is a
  154. * string, then the comparison will be true if and only if there is a
  155. * node in the node-set such that the result of performing the
  156. * comparison on the string-value of the node and the other string is
  157. * true.
  158. */
  159. boolean fls = left instanceof String;
  160. boolean frs = right instanceof String;
  161. if ((flns && frs) || (frns && fls))
  162. {
  163. /* Suppression is safe, as we know context produces Collection<Node> */
  164. @SuppressWarnings("unchecked")
  165. Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
  166. String s = fls ? (String) left : (String) right;
  167. boolean all = true;
  168. for (Node test : ns)
  169. {
  170. if (stringValue(test).equals(s))
  171. {
  172. if (!invert)
  173. {
  174. return true;
  175. }
  176. }
  177. else
  178. {
  179. all = false;
  180. }
  181. }
  182. return invert ? all : false;
  183. }
  184. /*
  185. * If one object to be compared is a node-set and the other is a
  186. * boolean, then the comparison will be true if and only if the result
  187. * of performing the comparison on the boolean and on the result of
  188. * converting the node-set to a boolean using the boolean function is
  189. * true.
  190. */
  191. boolean flb = left instanceof Boolean;
  192. boolean frb = right instanceof Boolean;
  193. if ((flns && frb) || (frns && flb))
  194. {
  195. /* Suppression is safe, as we know context produces Collection<Node> */
  196. @SuppressWarnings("unchecked")
  197. Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
  198. boolean b = flb ? ((Boolean) left).booleanValue() :
  199. ((Boolean) right).booleanValue();
  200. return _boolean(context, ns) == b;
  201. }
  202. /*
  203. * If at least one object to be compared is a boolean, then each object
  204. * to be compared is converted to a boolean as if by applying the
  205. * boolean function.
  206. */
  207. if (flb || frb)
  208. {
  209. boolean lb = flb ? ((Boolean) left).booleanValue() :
  210. _boolean(context, left);
  211. boolean rb = frb ? ((Boolean) right).booleanValue() :
  212. _boolean(context, right);
  213. return lb == rb;
  214. }
  215. /*
  216. * Otherwise, if at least one object to be compared is
  217. * a number, then each object to be compared is converted to a number as
  218. * if by applying the number function.
  219. */
  220. if (fln || frn)
  221. {
  222. double ln = fln ? ((Double) left).doubleValue() :
  223. _number(context, left);
  224. double rn = frn ? ((Double) right).doubleValue() :
  225. _number(context, right);
  226. return ln == rn;
  227. }
  228. /*
  229. * Otherwise, both objects to be
  230. * compared are converted to strings as if by applying the string
  231. * function.
  232. */
  233. String ls = fls ? (String) left : _string(context, left);
  234. String rs = frs ? (String) right : _string(context, right);
  235. return ls.equals(rs);
  236. }
  237. public Expr clone(Object context)
  238. {
  239. return new EqualityExpr(lhs.clone(context), rhs.clone(context), invert);
  240. }
  241. public boolean references(QName var)
  242. {
  243. return (lhs.references(var) || rhs.references(var));
  244. }
  245. public String toString()
  246. {
  247. if (invert)
  248. {
  249. return lhs + " != " + rhs;
  250. }
  251. else
  252. {
  253. return lhs + " = " + rhs;
  254. }
  255. }
  256. }