AtomicComparer.java :  » XML » XPath-Saxon » net » sf » saxon » sort » Java Open Source

Java Open Source » XML » XPath Saxon 
XPath Saxon » net » sf » saxon » sort » AtomicComparer.java
package net.sf.saxon.sort;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.value.AtomicValue;
import net.sf.saxon.value.CalendarValue;
import net.sf.saxon.value.StringValue;
import net.sf.saxon.value.UntypedAtomicValue;
import net.sf.saxon.Configuration;

import java.text.Collator;
import java.util.Comparator;

/**
 * A Comparator used for comparing atomic values of arbitrary item types. It encapsulates
 * a Collator that is used when the values to be compared are strings. It also supports
 * a separate method for testing equality of items, which can be used for data types that
 * are not ordered.
 *
 * @author Michael H. Kay
 *
 */

public class AtomicComparer implements Comparator, java.io.Serializable {

    // TODO: create specialized AtomicComparers (and/or AtomicSortComparers) for particular data types

    private Comparator collator;
    private XPathContext conversionContext;

    /**
     * Create an AtomicComparer
     * @param collator the collation to be used
     * @param conversion a context, used when converting untyped atomic values to the target type.
     */

    public AtomicComparer(Comparator collator, XPathContext conversion) {
        this.collator = collator;
        if (collator == null) {
            this.collator = CodepointCollator.getInstance();
        }
        this.conversionContext = conversion;
    }

    public AtomicComparer(Comparator collator, Configuration config) {
        this.collator = collator;
        if (collator == null) {
            this.collator = CodepointCollator.getInstance();
        }
        this.conversionContext = config.getConversionContext();
    }

    /**
    * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic
    * values are compared as if they were strings; if different semantics are wanted, the conversion
    * must be done by the caller.
    * @param a the first object to be compared. It is intended that this should be an instance
    * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the
    * collator is used to compare the values, otherwise the value must implement the java.util.Comparable
    * interface.
    * @param b the second object to be compared. This must be comparable with the first object: for
    * example, if one is a string, they must both be strings.
    * @return <0 if a<b, 0 if a=b, >0 if a>b
    * @throws ClassCastException if the objects are not comparable
    */

    public int compare(Object a, Object b) {

        // System.err.println("Comparing " + a.getClass() + "(" + a + ") with " + b.getClass() + "(" + b + ") using " + collator);

        if (a instanceof AtomicValue && !((AtomicValue)a).hasBuiltInType()) {
            a = ((AtomicValue)a).getPrimitiveValue();
        }
        if (b instanceof AtomicValue && !((AtomicValue)b).hasBuiltInType()) {
            b = ((AtomicValue)b).getPrimitiveValue();
        }

        if (a instanceof UntypedAtomicValue) {
            return ((UntypedAtomicValue)a).compareTo(b, collator, conversionContext);
        } else if (b instanceof UntypedAtomicValue) {
            return -((UntypedAtomicValue)b).compareTo(a, collator, conversionContext);
        } else if (a instanceof CalendarValue && b instanceof CalendarValue) {
            return ((CalendarValue)a).compareTo((CalendarValue)b, conversionContext);
        } else if (a instanceof Comparable) {
            return ((Comparable)a).compareTo(b);
        } else if (a instanceof StringValue) {
            return collator.compare(((StringValue)a).getStringValue(), ((StringValue)b).getStringValue());
        } else {
            throw new ClassCastException("Objects are not comparable (" + a.getClass() + ", " + b.getClass() + ')');
        }
    }

    /**
    * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic
    * values are compared by converting to the type of the other operand.
    * @param a the first object to be compared. It is intended that this should be an instance
    * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the
    * collator is used to compare the values, otherwise the value must implement the equals() method.
    * @param b the second object to be compared. This must be comparable with the first object: for
    * example, if one is a string, they must both be strings.
    * @return <0 if a<b, 0 if a=b, >0 if a>b
    * @throws ClassCastException if the objects are not comparable
    */

    public boolean comparesEqual(Object a, Object b) {
        // System.err.println("Comparing " + a.getClass() + ": " + a + " with " + b.getClass() + ": " + b);

        if (a instanceof AtomicValue && !((AtomicValue)a).hasBuiltInType()) {
            a = ((AtomicValue)a).getPrimitiveValue();
        }
        if (b instanceof AtomicValue && !((AtomicValue)b).hasBuiltInType()) {
            b = ((AtomicValue)b).getPrimitiveValue();
        }

        if (a instanceof UntypedAtomicValue) {
            return ((UntypedAtomicValue)a).compareTo(b, collator, conversionContext) == 0;
        } else if (b instanceof UntypedAtomicValue) {
            return ((UntypedAtomicValue)b).compareTo(a, collator, conversionContext) == 0;
        } else if (a instanceof StringValue) {
            return collator.compare(((StringValue)a).getStringValue(), ((StringValue)b).getStringValue()) == 0;
        } else if (a instanceof CalendarValue && b instanceof CalendarValue) {
            return ((CalendarValue)a).compareTo((CalendarValue)b, conversionContext) == 0;
        } else if (a instanceof String) {
            return collator.compare(a, b) == 0;
        } else {
            return a.equals(b);
        }
    }

    /**
    * Get a comparison key for an object. This must satisfy the rule that if two objects are equal,
    * then their comparison keys are equal, and vice versa. There is no requirement that the
    * comparison keys should reflect the ordering of the underlying objects.
    */

    public Object getComparisonKey(Object a) {

        if (a instanceof AtomicValue && !((AtomicValue)a).hasBuiltInType()) {
            a = ((AtomicValue)a).getPrimitiveValue();
        }

        if (a instanceof StringValue) {
            if (collator instanceof Collator) {
                return ((Collator)collator).getCollationKey(((StringValue)a).getStringValue());
            } else {
                return ((StringValue)a).getStringValue();
            }
        } else {
            return a;
        }
    }


}


//
// The contents of this file are subject to the Mozilla Public License Version 1.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.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is: all this file.
//
// The Initial Developer of the Original Code is Michael H. Kay
//
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
//
// Contributor(s): none
//
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.