1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xpath.objects;
  58. //import org.w3c.dom.Node;
  59. //import org.w3c.dom.Text;
  60. //import org.w3c.dom.DocumentFragment;
  61. import org.w3c.dom.traversal.NodeIterator;
  62. import org.w3c.dom.NodeList;
  63. import org.apache.xml.dtm.DTM;
  64. import org.apache.xml.dtm.DTMIterator;
  65. import org.apache.xml.dtm.DTMManager;
  66. import org.apache.xpath.DOMHelper;
  67. import org.apache.xpath.XPathContext;
  68. import org.apache.xpath.NodeSetDTM;
  69. import org.apache.xpath.axes.ContextNodeList;
  70. import org.apache.xpath.axes.NodeSequence;
  71. import org.apache.xml.utils.StringVector;
  72. import org.apache.xml.utils.XMLString;
  73. /**
  74. * <meta name="usage" content="general"/>
  75. * This class represents an XPath nodeset object, and is capable of
  76. * converting the nodeset to other types, such as a string.
  77. */
  78. public class XNodeSet extends NodeSequence
  79. {
  80. /**
  81. * Default constructor for derived objects.
  82. */
  83. protected XNodeSet()
  84. {
  85. }
  86. /**
  87. * Construct a XNodeSet object.
  88. *
  89. * @param val Value of the XNodeSet object
  90. */
  91. public XNodeSet(DTMIterator val)
  92. {
  93. super();
  94. if(val instanceof XNodeSet)
  95. {
  96. setIter(((XNodeSet)val).m_iter);
  97. m_dtmMgr = ((XNodeSet)val).m_dtmMgr;
  98. m_last = ((XNodeSet)val).m_last;
  99. if(!((XNodeSet)val).hasCache())
  100. ((XNodeSet)val).setShouldCacheNodes(true);
  101. m_obj = ((XNodeSet)val).m_obj;
  102. }
  103. else
  104. setIter(val);
  105. }
  106. /**
  107. * Construct a XNodeSet object.
  108. *
  109. * @param val Value of the XNodeSet object
  110. */
  111. public XNodeSet(XNodeSet val)
  112. {
  113. super();
  114. setIter(val.m_iter);
  115. m_dtmMgr = val.m_dtmMgr;
  116. m_last = val.m_last;
  117. if(!val.hasCache())
  118. val.setShouldCacheNodes(true);
  119. m_obj = val.m_obj;
  120. }
  121. /**
  122. * Construct an empty XNodeSet object. This is used to create a mutable
  123. * nodeset to which random nodes may be added.
  124. */
  125. public XNodeSet(DTMManager dtmMgr)
  126. {
  127. super(dtmMgr);
  128. }
  129. /**
  130. * Construct a XNodeSet object for one node.
  131. *
  132. * @param n Node to add to the new XNodeSet object
  133. */
  134. public XNodeSet(int n, DTMManager dtmMgr)
  135. {
  136. super(new NodeSetDTM(dtmMgr));
  137. m_dtmMgr = dtmMgr;
  138. if (DTM.NULL != n)
  139. {
  140. ((NodeSetDTM) m_obj).addNode(n);
  141. m_last = 1;
  142. }
  143. else
  144. m_last = 0;
  145. }
  146. /**
  147. * Tell that this is a CLASS_NODESET.
  148. *
  149. * @return type CLASS_NODESET
  150. */
  151. public int getType()
  152. {
  153. return CLASS_NODESET;
  154. }
  155. /**
  156. * Given a request type, return the equivalent string.
  157. * For diagnostic purposes.
  158. *
  159. * @return type string "#NODESET"
  160. */
  161. public String getTypeString()
  162. {
  163. return "#NODESET";
  164. }
  165. /**
  166. * Get numeric value of the string conversion from a single node.
  167. *
  168. * @param n Node to convert
  169. *
  170. * @return numeric value of the string conversion from a single node.
  171. */
  172. public double getNumberFromNode(int n)
  173. {
  174. XMLString xstr = m_dtmMgr.getDTM(n).getStringValue(n);
  175. return xstr.toDouble();
  176. }
  177. /**
  178. * Cast result object to a number.
  179. *
  180. * @return numeric value of the string conversion from the
  181. * next node in the NodeSetDTM, or NAN if no node was found
  182. */
  183. public double num()
  184. {
  185. int node = item(0);
  186. return (node != DTM.NULL) ? getNumberFromNode(node) : Double.NaN;
  187. }
  188. /**
  189. * Cast result object to a number, but allow side effects, such as the
  190. * incrementing of an iterator.
  191. *
  192. * @return numeric value of the string conversion from the
  193. * next node in the NodeSetDTM, or NAN if no node was found
  194. */
  195. public double numWithSideEffects()
  196. {
  197. int node = nextNode();
  198. return (node != DTM.NULL) ? getNumberFromNode(node) : Double.NaN;
  199. }
  200. /**
  201. * Cast result object to a boolean.
  202. *
  203. * @return True if there is a next node in the nodeset
  204. */
  205. public boolean bool()
  206. {
  207. return (item(0) != DTM.NULL);
  208. }
  209. /**
  210. * Cast result object to a boolean, but allow side effects, such as the
  211. * incrementing of an iterator.
  212. *
  213. * @return True if there is a next node in the nodeset
  214. */
  215. public boolean boolWithSideEffects()
  216. {
  217. return (nextNode() != DTM.NULL);
  218. }
  219. /**
  220. * Get the string conversion from a single node.
  221. *
  222. * @param n Node to convert
  223. *
  224. * @return the string conversion from a single node.
  225. */
  226. public XMLString getStringFromNode(int n)
  227. {
  228. // %OPT%
  229. // I guess we'll have to get a static instance of the DTM manager...
  230. if(DTM.NULL != n)
  231. {
  232. return m_dtmMgr.getDTM(n).getStringValue(n);
  233. }
  234. else
  235. {
  236. return org.apache.xpath.objects.XString.EMPTYSTRING;
  237. }
  238. }
  239. /**
  240. * Directly call the
  241. * characters method on the passed ContentHandler for the
  242. * string-value. Multiple calls to the
  243. * ContentHandler's characters methods may well occur for a single call to
  244. * this method.
  245. *
  246. * @param ch A non-null reference to a ContentHandler.
  247. *
  248. * @throws org.xml.sax.SAXException
  249. */
  250. public void dispatchCharactersEvents(org.xml.sax.ContentHandler ch)
  251. throws org.xml.sax.SAXException
  252. {
  253. int node = item(0);
  254. if(node != DTM.NULL)
  255. {
  256. m_dtmMgr.getDTM(node).dispatchCharactersEvents(node, ch, false);
  257. }
  258. }
  259. /**
  260. * Cast result object to an XMLString.
  261. *
  262. * @return The document fragment node data or the empty string.
  263. */
  264. public XMLString xstr()
  265. {
  266. int node = item(0);
  267. return (node != DTM.NULL) ? getStringFromNode(node) : XString.EMPTYSTRING;
  268. }
  269. /**
  270. * Cast result object to a string.
  271. *
  272. * @return The string this wraps or the empty string if null
  273. */
  274. public void appendToFsb(org.apache.xml.utils.FastStringBuffer fsb)
  275. {
  276. XString xstring = (XString)xstr();
  277. xstring.appendToFsb(fsb);
  278. }
  279. /**
  280. * Cast result object to a string.
  281. *
  282. * @return the string conversion from the next node in the nodeset
  283. * or "" if there is no next node
  284. */
  285. public String str()
  286. {
  287. int node = item(0);
  288. return (node != DTM.NULL) ? getStringFromNode(node).toString() : "";
  289. }
  290. /**
  291. * Return a java object that's closest to the representation
  292. * that should be handed to an extension.
  293. *
  294. * @return The object that this class wraps
  295. */
  296. public Object object()
  297. {
  298. if(null == m_obj)
  299. return this;
  300. else
  301. return m_obj;
  302. }
  303. // %REVIEW%
  304. // hmmm...
  305. // /**
  306. // * Cast result object to a result tree fragment.
  307. // *
  308. // * @param support The XPath context to use for the conversion
  309. // *
  310. // * @return the nodeset as a result tree fragment.
  311. // */
  312. // public DocumentFragment rtree(XPathContext support)
  313. // {
  314. // DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  315. // DocumentBuilder db = dbf.newDocumentBuilder();
  316. // Document myDoc = db.newDocument();
  317. //
  318. // DocumentFragment docFrag = myDoc.createDocumentFragment();
  319. //
  320. // DTMIterator nl = iter();
  321. // int node;
  322. //
  323. // while (DTM.NULL != (node = nl.nextNode()))
  324. // {
  325. // frag.appendChild(node, true, true);
  326. // }
  327. //
  328. // return frag.getDocument();
  329. // }
  330. /**
  331. * Cast result object to a nodelist.
  332. *
  333. * @return a NodeIterator.
  334. *
  335. * @throws javax.xml.transform.TransformerException
  336. */
  337. public NodeIterator nodeset() throws javax.xml.transform.TransformerException
  338. {
  339. return new org.apache.xml.dtm.ref.DTMNodeIterator(iter());
  340. }
  341. /**
  342. * Cast result object to a nodelist.
  343. *
  344. * @return a NodeList.
  345. *
  346. * @throws javax.xml.transform.TransformerException
  347. */
  348. public NodeList nodelist() throws javax.xml.transform.TransformerException
  349. {
  350. return new org.apache.xml.dtm.ref.DTMNodeList(iter());
  351. }
  352. // /**
  353. // * Return a java object that's closest to the representation
  354. // * that should be handed to an extension.
  355. // *
  356. // * @return The object that this class wraps
  357. // */
  358. // public Object object()
  359. // {
  360. // return new org.apache.xml.dtm.ref.DTMNodeList(iter());
  361. // }
  362. /**
  363. * Return the iterator without cloning, etc.
  364. */
  365. public DTMIterator iterRaw()
  366. {
  367. return this;
  368. }
  369. public void release(DTMIterator iter)
  370. {
  371. }
  372. /**
  373. * Cast result object to a nodelist.
  374. *
  375. * @return The nodeset as a nodelist
  376. */
  377. public DTMIterator iter()
  378. {
  379. try
  380. {
  381. if(hasCache())
  382. return cloneWithReset();
  383. else
  384. return this; // don't bother to clone... won't do any good!
  385. }
  386. catch (CloneNotSupportedException cnse)
  387. {
  388. throw new RuntimeException(cnse.getMessage());
  389. }
  390. }
  391. /**
  392. * Get a fresh copy of the object. For use with variables.
  393. *
  394. * @return A fresh nodelist.
  395. */
  396. public XObject getFresh()
  397. {
  398. try
  399. {
  400. if(hasCache())
  401. return (XObject)cloneWithReset();
  402. else
  403. return this; // don't bother to clone... won't do any good!
  404. }
  405. catch (CloneNotSupportedException cnse)
  406. {
  407. throw new RuntimeException(cnse.getMessage());
  408. }
  409. }
  410. /**
  411. * Cast result object to a mutableNodeset.
  412. *
  413. * @return The nodeset as a mutableNodeset
  414. */
  415. public NodeSetDTM mutableNodeset()
  416. {
  417. NodeSetDTM mnl;
  418. if(m_obj instanceof NodeSetDTM)
  419. {
  420. mnl = (NodeSetDTM) m_obj;
  421. }
  422. else
  423. {
  424. mnl = new NodeSetDTM(iter());
  425. m_obj = mnl;
  426. setCurrentPos(0);
  427. }
  428. return mnl;
  429. }
  430. /** Less than comparator */
  431. static LessThanComparator S_LT = new LessThanComparator();
  432. /** Less than or equal comparator */
  433. static LessThanOrEqualComparator S_LTE = new LessThanOrEqualComparator();
  434. /** Greater than comparator */
  435. static GreaterThanComparator S_GT = new GreaterThanComparator();
  436. /** Greater than or equal comparator */
  437. static GreaterThanOrEqualComparator S_GTE =
  438. new GreaterThanOrEqualComparator();
  439. /** Equal comparator */
  440. static EqualComparator S_EQ = new EqualComparator();
  441. /** Not equal comparator */
  442. static NotEqualComparator S_NEQ = new NotEqualComparator();
  443. /**
  444. * Tell if one object is less than the other.
  445. *
  446. * @param obj2 Object to compare this nodeset to
  447. * @param comparator Comparator to use
  448. *
  449. * @return See the comments below for each object type comparison
  450. *
  451. * @throws javax.xml.transform.TransformerException
  452. */
  453. public boolean compare(XObject obj2, Comparator comparator)
  454. throws javax.xml.transform.TransformerException
  455. {
  456. boolean result = false;
  457. int type = obj2.getType();
  458. if (XObject.CLASS_NODESET == type)
  459. {
  460. // %OPT% This should be XMLString based instead of string based...
  461. // From http://www.w3.org/TR/xpath:
  462. // If both objects to be compared are node-sets, then the comparison
  463. // will be true if and only if there is a node in the first node-set
  464. // and a node in the second node-set such that the result of performing
  465. // the comparison on the string-values of the two nodes is true.
  466. // Note this little gem from the draft:
  467. // NOTE: If $x is bound to a node-set, then $x="foo"
  468. // does not mean the same as not($x!="foo"): the former
  469. // is true if and only if some node in $x has the string-value
  470. // foo; the latter is true if and only if all nodes in $x have
  471. // the string-value foo.
  472. DTMIterator list1 = iterRaw();
  473. DTMIterator list2 = ((XNodeSet) obj2).iterRaw();
  474. int node1;
  475. java.util.Vector node2Strings = null;
  476. while (DTM.NULL != (node1 = list1.nextNode()))
  477. {
  478. XMLString s1 = getStringFromNode(node1);
  479. if (null == node2Strings)
  480. {
  481. int node2;
  482. while (DTM.NULL != (node2 = list2.nextNode()))
  483. {
  484. XMLString s2 = getStringFromNode(node2);
  485. if (comparator.compareStrings(s1, s2))
  486. {
  487. result = true;
  488. break;
  489. }
  490. if (null == node2Strings)
  491. node2Strings = new java.util.Vector();
  492. node2Strings.addElement(s2);
  493. }
  494. }
  495. else
  496. {
  497. int n = node2Strings.size();
  498. for (int i = 0; i < n; i++)
  499. {
  500. if (comparator.compareStrings(s1, (XMLString)node2Strings.elementAt(i)))
  501. {
  502. result = true;
  503. break;
  504. }
  505. }
  506. }
  507. }
  508. list1.reset();
  509. list2.reset();
  510. }
  511. else if (XObject.CLASS_BOOLEAN == type)
  512. {
  513. // From http://www.w3.org/TR/xpath:
  514. // If one object to be compared is a node-set and the other is a boolean,
  515. // then the comparison will be true if and only if the result of
  516. // performing the comparison on the boolean and on the result of
  517. // converting the node-set to a boolean using the boolean function
  518. // is true.
  519. double num1 = bool() ? 1.0 : 0.0;
  520. double num2 = obj2.num();
  521. result = comparator.compareNumbers(num1, num2);
  522. }
  523. else if (XObject.CLASS_NUMBER == type)
  524. {
  525. // From http://www.w3.org/TR/xpath:
  526. // If one object to be compared is a node-set and the other is a number,
  527. // then the comparison will be true if and only if there is a
  528. // node in the node-set such that the result of performing the
  529. // comparison on the number to be compared and on the result of
  530. // converting the string-value of that node to a number using
  531. // the number function is true.
  532. DTMIterator list1 = iterRaw();
  533. double num2 = obj2.num();
  534. int node;
  535. while (DTM.NULL != (node = list1.nextNode()))
  536. {
  537. double num1 = getNumberFromNode(node);
  538. if (comparator.compareNumbers(num1, num2))
  539. {
  540. result = true;
  541. break;
  542. }
  543. }
  544. list1.reset();
  545. }
  546. else if (XObject.CLASS_RTREEFRAG == type)
  547. {
  548. XMLString s2 = obj2.xstr();
  549. DTMIterator list1 = iterRaw();
  550. int node;
  551. while (DTM.NULL != (node = list1.nextNode()))
  552. {
  553. XMLString s1 = getStringFromNode(node);
  554. if (comparator.compareStrings(s1, s2))
  555. {
  556. result = true;
  557. break;
  558. }
  559. }
  560. list1.reset();
  561. }
  562. else if (XObject.CLASS_STRING == type)
  563. {
  564. // From http://www.w3.org/TR/xpath:
  565. // If one object to be compared is a node-set and the other is a
  566. // string, then the comparison will be true if and only if there
  567. // is a node in the node-set such that the result of performing
  568. // the comparison on the string-value of the node and the other
  569. // string is true.
  570. XMLString s2 = obj2.xstr();
  571. DTMIterator list1 = iterRaw();
  572. int node;
  573. while (DTM.NULL != (node = list1.nextNode()))
  574. {
  575. XMLString s1 = getStringFromNode(node);
  576. if (comparator.compareStrings(s1, s2))
  577. {
  578. result = true;
  579. break;
  580. }
  581. }
  582. list1.reset();
  583. }
  584. else
  585. {
  586. result = comparator.compareNumbers(this.num(), obj2.num());
  587. }
  588. return result;
  589. }
  590. /**
  591. * Tell if one object is less than the other.
  592. *
  593. * @param obj2 object to compare this nodeset to
  594. *
  595. * @return see this.compare(...)
  596. *
  597. * @throws javax.xml.transform.TransformerException
  598. */
  599. public boolean lessThan(XObject obj2) throws javax.xml.transform.TransformerException
  600. {
  601. return compare(obj2, S_LT);
  602. }
  603. /**
  604. * Tell if one object is less than or equal to the other.
  605. *
  606. * @param obj2 object to compare this nodeset to
  607. *
  608. * @return see this.compare(...)
  609. *
  610. * @throws javax.xml.transform.TransformerException
  611. */
  612. public boolean lessThanOrEqual(XObject obj2) throws javax.xml.transform.TransformerException
  613. {
  614. return compare(obj2, S_LTE);
  615. }
  616. /**
  617. * Tell if one object is less than the other.
  618. *
  619. * @param obj2 object to compare this nodeset to
  620. *
  621. * @return see this.compare(...)
  622. *
  623. * @throws javax.xml.transform.TransformerException
  624. */
  625. public boolean greaterThan(XObject obj2) throws javax.xml.transform.TransformerException
  626. {
  627. return compare(obj2, S_GT);
  628. }
  629. /**
  630. * Tell if one object is less than the other.
  631. *
  632. * @param obj2 object to compare this nodeset to
  633. *
  634. * @return see this.compare(...)
  635. *
  636. * @throws javax.xml.transform.TransformerException
  637. */
  638. public boolean greaterThanOrEqual(XObject obj2)
  639. throws javax.xml.transform.TransformerException
  640. {
  641. return compare(obj2, S_GTE);
  642. }
  643. /**
  644. * Tell if two objects are functionally equal.
  645. *
  646. * @param obj2 object to compare this nodeset to
  647. *
  648. * @return see this.compare(...)
  649. *
  650. * @throws javax.xml.transform.TransformerException
  651. */
  652. public boolean equals(XObject obj2)
  653. {
  654. try
  655. {
  656. return compare(obj2, S_EQ);
  657. }
  658. catch(javax.xml.transform.TransformerException te)
  659. {
  660. throw new org.apache.xml.utils.WrappedRuntimeException(te);
  661. }
  662. }
  663. /**
  664. * Tell if two objects are functionally not equal.
  665. *
  666. * @param obj2 object to compare this nodeset to
  667. *
  668. * @return see this.compare(...)
  669. *
  670. * @throws javax.xml.transform.TransformerException
  671. */
  672. public boolean notEquals(XObject obj2) throws javax.xml.transform.TransformerException
  673. {
  674. return compare(obj2, S_NEQ);
  675. }
  676. }
  677. /**
  678. * compares nodes for various boolean operations.
  679. */
  680. abstract class Comparator
  681. {
  682. /**
  683. * Compare two strings
  684. *
  685. *
  686. * @param s1 First string to compare
  687. * @param s2 Second String to compare
  688. *
  689. * @return Whether the strings are equal or not
  690. */
  691. abstract boolean compareStrings(XMLString s1, XMLString s2);
  692. /**
  693. * Compare two numbers
  694. *
  695. *
  696. * @param n1 First number to compare
  697. * @param n2 Second number to compare
  698. *
  699. * @return Whether the numbers are equal or not
  700. */
  701. abstract boolean compareNumbers(double n1, double n2);
  702. }
  703. /**
  704. * Compare strings or numbers for less than.
  705. */
  706. class LessThanComparator extends Comparator
  707. {
  708. /**
  709. * Compare two strings for less than.
  710. *
  711. *
  712. * @param s1 First string to compare
  713. * @param s2 Second String to compare
  714. *
  715. * @return True if s1 is less than s2
  716. */
  717. boolean compareStrings(XMLString s1, XMLString s2)
  718. {
  719. return (s1.toDouble() < s2.toDouble());
  720. // return s1.compareTo(s2) < 0;
  721. }
  722. /**
  723. * Compare two numbers for less than.
  724. *
  725. *
  726. * @param n1 First number to compare
  727. * @param n2 Second number to compare
  728. *
  729. * @return true if n1 is less than n2
  730. */
  731. boolean compareNumbers(double n1, double n2)
  732. {
  733. return n1 < n2;
  734. }
  735. }
  736. /**
  737. * Compare strings or numbers for less than or equal.
  738. */
  739. class LessThanOrEqualComparator extends Comparator
  740. {
  741. /**
  742. * Compare two strings for less than or equal.
  743. *
  744. *
  745. * @param s1 First string to compare
  746. * @param s2 Second String to compare
  747. *
  748. * @return true if s1 is less than or equal to s2
  749. */
  750. boolean compareStrings(XMLString s1, XMLString s2)
  751. {
  752. return (s1.toDouble() <= s2.toDouble());
  753. // return s1.compareTo(s2) <= 0;
  754. }
  755. /**
  756. * Compare two numbers for less than or equal.
  757. *
  758. *
  759. * @param n1 First number to compare
  760. * @param n2 Second number to compare
  761. *
  762. * @return true if n1 is less than or equal to n2
  763. */
  764. boolean compareNumbers(double n1, double n2)
  765. {
  766. return n1 <= n2;
  767. }
  768. }
  769. /**
  770. * Compare strings or numbers for greater than.
  771. */
  772. class GreaterThanComparator extends Comparator
  773. {
  774. /**
  775. * Compare two strings for greater than.
  776. *
  777. *
  778. * @param s1 First string to compare
  779. * @param s2 Second String to compare
  780. *
  781. * @return true if s1 is greater than s2
  782. */
  783. boolean compareStrings(XMLString s1, XMLString s2)
  784. {
  785. return (s1.toDouble() > s2.toDouble());
  786. // return s1.compareTo(s2) > 0;
  787. }
  788. /**
  789. * Compare two numbers for greater than.
  790. *
  791. *
  792. * @param n1 First number to compare
  793. * @param n2 Second number to compare
  794. *
  795. * @return true if n1 is greater than n2
  796. */
  797. boolean compareNumbers(double n1, double n2)
  798. {
  799. return n1 > n2;
  800. }
  801. }
  802. /**
  803. * Compare strings or numbers for greater than or equal.
  804. */
  805. class GreaterThanOrEqualComparator extends Comparator
  806. {
  807. /**
  808. * Compare two strings for greater than or equal.
  809. *
  810. *
  811. * @param s1 First string to compare
  812. * @param s2 Second String to compare
  813. *
  814. * @return true if s1 is greater than or equal to s2
  815. */
  816. boolean compareStrings(XMLString s1, XMLString s2)
  817. {
  818. return (s1.toDouble() >= s2.toDouble());
  819. // return s1.compareTo(s2) >= 0;
  820. }
  821. /**
  822. * Compare two numbers for greater than or equal.
  823. *
  824. *
  825. * @param n1 First number to compare
  826. * @param n2 Second number to compare
  827. *
  828. * @return true if n1 is greater than or equal to n2
  829. */
  830. boolean compareNumbers(double n1, double n2)
  831. {
  832. return n1 >= n2;
  833. }
  834. }
  835. /**
  836. * Compare strings or numbers for equality.
  837. */
  838. class EqualComparator extends Comparator
  839. {
  840. /**
  841. * Compare two strings for equality.
  842. *
  843. *
  844. * @param s1 First string to compare
  845. * @param s2 Second String to compare
  846. *
  847. * @return true if s1 is equal to s2
  848. */
  849. boolean compareStrings(XMLString s1, XMLString s2)
  850. {
  851. return s1.equals(s2);
  852. }
  853. /**
  854. * Compare two numbers for equality.
  855. *
  856. *
  857. * @param n1 First number to compare
  858. * @param n2 Second number to compare
  859. *
  860. * @return true if n1 is equal to n2
  861. */
  862. boolean compareNumbers(double n1, double n2)
  863. {
  864. return n1 == n2;
  865. }
  866. }
  867. /**
  868. * Compare strings or numbers for non-equality.
  869. */
  870. class NotEqualComparator extends Comparator
  871. {
  872. /**
  873. * Compare two strings for non-equality.
  874. *
  875. *
  876. * @param s1 First string to compare
  877. * @param s2 Second String to compare
  878. *
  879. * @return true if s1 is not equal to s2
  880. */
  881. boolean compareStrings(XMLString s1, XMLString s2)
  882. {
  883. return !s1.equals(s2);
  884. }
  885. /**
  886. * Compare two numbers for non-equality.
  887. *
  888. *
  889. * @param n1 First number to compare
  890. * @param n2 Second number to compare
  891. *
  892. * @return true if n1 is not equal to n2
  893. */
  894. boolean compareNumbers(double n1, double n2)
  895. {
  896. return n1 != n2;
  897. }
  898. }