Package client.net.sf.saxon.ce.functions

Source Code of client.net.sf.saxon.ce.functions.DeepEqual

package client.net.sf.saxon.ce.functions;
import client.net.sf.saxon.ce.Configuration;
import client.net.sf.saxon.ce.expr.Expression;
import client.net.sf.saxon.ce.expr.ExpressionVisitor;
import client.net.sf.saxon.ce.expr.XPathContext;
import client.net.sf.saxon.ce.expr.sort.GenericAtomicComparer;
import client.net.sf.saxon.ce.lib.NamespaceConstant;
import client.net.sf.saxon.ce.om.*;
import client.net.sf.saxon.ce.pattern.NameTest;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.iter.AxisIterator;
import client.net.sf.saxon.ce.type.Type;
import client.net.sf.saxon.ce.value.AtomicValue;
import client.net.sf.saxon.ce.value.BooleanValue;

/**
* XSLT 2.0 deep-equal() function.
* Supports deep comparison of two sequences (of nodes and/or atomic values)
* optionally using a collation
*/

public class DeepEqual extends CollatingFunction {

    public DeepEqual newInstance() {
        return new DeepEqual();
    }

    private transient Configuration config = null;

    /**
    * preEvaluate: if all arguments are known statically, evaluate early
     * @param visitor an expression visitor
     */

    public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException {
        config = visitor.getConfiguration();
        return super.preEvaluate(visitor);
    }

    /**
    * Evaluate the expression
    */

    public Item evaluateItem(XPathContext context) throws XPathException {
        GenericAtomicComparer collator = getAtomicComparer(2, context);

        SequenceIterator op1 = argument[0].iterate(context);
        SequenceIterator op2 = argument[1].iterate(context);

        Configuration config =
                (this.config!=null ? this.config : context.getConfiguration());
        try {
            return BooleanValue.get(deepEquals(op1, op2, collator, config));
        } catch (XPathException e) {
            e.maybeSetLocation(getSourceLocator());
            e.maybeSetContext(context);
            throw e;
        }
    }

    /**
     * Determine when two sequences are deep-equal
     * @param op1 the first sequence
     * @param op2 the second sequence
     * @param collator the collator to be used
     * @param config the configuration (gives access to the NamePool)
     * @return true if the sequences are deep-equal
     * @throws XPathException if either sequence contains a function item
     */

    private static boolean deepEquals(SequenceIterator op1, SequenceIterator op2,
                                     GenericAtomicComparer collator, Configuration config)
    throws XPathException {
        boolean result = true;

        try {

            while (true) {
                Item item1 = op1.next();
                Item item2 = op2.next();

                if (item1 == null && item2 == null) {
                    break;
                }

                if (item1 == null || item2 == null) {
                    result = false;
                    break;
                }

                if (item1 instanceof NodeInfo) {
                    if (item2 instanceof NodeInfo) {
                        if (!deepEquals((NodeInfo)item1, (NodeInfo)item2, collator, config)) {
                            result = false;
                            break;
                        }
                    } else {
                        result = false;
                        break;
                    }
                } else {
                    if (item2 instanceof NodeInfo) {
                        result = false;
                        break;
                    } else {
                        AtomicValue av1 = ((AtomicValue)item1);
                        AtomicValue av2 = ((AtomicValue)item2);
                        if (av1.isNaN() && av2.isNaN()) {
                            // treat as equal, no action
                        } else if (!collator.comparesEqual(av1, av2)) {
                            result = false;
                            break;
                        }
                    }
                }
            } // end while

        } catch (ClassCastException err) {
            // this will happen if the sequences contain non-comparable values
            // comparison errors are masked
            result = false;
        } catch (XPathException err) {
            // comparison errors are masked
            if ("FOTY0015".equals(err.getErrorCodeLocalPart()) && NamespaceConstant.ERR.equals(err.getErrorCodeNamespace())) {
                throw err;
            }
            result = false;
        }

        return result;
    }

    /**
    * Determine whether two nodes are deep-equal
    */

    private static boolean deepEquals(NodeInfo n1, NodeInfo n2,
                                      GenericAtomicComparer collator, Configuration config)
    throws XPathException {
        // shortcut: a node is always deep-equal to itself
        if (n1.isSameNodeInfo(n2)) return true;

        if (n1.getNodeKind() != n2.getNodeKind()) {
            return false;
        }

        final NamePool pool = config.getNamePool();
        switch (n1.getNodeKind()) {
            case Type.ELEMENT:
                if (n1.getFingerprint() != n2.getFingerprint()) {
                    return false;
                }
                AxisIterator a1 = n1.iterateAxis(Axis.ATTRIBUTE);
                AxisIterator a2 = n2.iterateAxis(Axis.ATTRIBUTE);
                if (Count.count(a1.getAnother()) != Count.count(a2)) {
                    return false;
                }
                while (true) {
                    NodeInfo att1 = (NodeInfo)a1.next();
                    if (att1 == null) break;

                    AxisIterator a2iter = n2.iterateAxis(Axis.ATTRIBUTE,
                                            new NameTest(Type.ATTRIBUTE, att1.getFingerprint(), pool));
                    NodeInfo att2 = (NodeInfo)a2iter.next();

                    if (att2==null) {
                        return false;
                    }
                    if (!deepEquals(att1, att2, collator, config)) {
                        return false;
                    }
                }

                // fall through
            case Type.DOCUMENT:
                AxisIterator c1 = n1.iterateAxis(Axis.CHILD);
                AxisIterator c2 = n2.iterateAxis(Axis.CHILD);
                while (true) {
                    NodeInfo d1 = (NodeInfo)c1.next();
                    while (d1 != null && isIgnorable(d1))  {
                        d1 = (NodeInfo)c1.next();
                    }
                    NodeInfo d2 = (NodeInfo)c2.next();
                    while (d2 != null && isIgnorable(d2))  {
                        d2 = (NodeInfo)c2.next();
                    }
                    if (d1 == null || d2 == null) {
                        return (d1 == d2);
                    }
                    if (!deepEquals(d1, d2, collator, config)) {
                        return false;
                    }
                }

            case Type.ATTRIBUTE:
            case Type.PROCESSING_INSTRUCTION:
            case Type.NAMESPACE:
            case Type.TEXT:
            case Type.COMMENT:
                return (n1.getFingerprint() == n2.getFingerprint() &&
                        collator.comparesEqual(n1.getTypedValue(), n2.getTypedValue()));


            default:
                throw new IllegalArgumentException("Unknown node type");
        }
    }

    private static boolean isIgnorable(NodeInfo node) {
        final int kind = node.getNodeKind();
        if (kind == Type.COMMENT) {
            return true;
        } else if (kind == Type.PROCESSING_INSTRUCTION) {
            return true;
        }
        return false;
    }


}

// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.
TOP

Related Classes of client.net.sf.saxon.ce.functions.DeepEqual

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.