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

Source Code of client.net.sf.saxon.ce.functions.Id$IdMappingFunction

package client.net.sf.saxon.ce.functions;

import client.net.sf.saxon.ce.expr.*;
import client.net.sf.saxon.ce.expr.sort.DocumentOrderIterator;
import client.net.sf.saxon.ce.expr.sort.LocalOrderComparer;
import client.net.sf.saxon.ce.om.DocumentInfo;
import client.net.sf.saxon.ce.om.Item;
import client.net.sf.saxon.ce.om.NodeInfo;
import client.net.sf.saxon.ce.om.SequenceIterator;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.iter.ListIterator;
import client.net.sf.saxon.ce.tree.iter.SingletonIterator;
import client.net.sf.saxon.ce.tree.util.StringTokenizer;
import client.net.sf.saxon.ce.type.ItemType;
import client.net.sf.saxon.ce.type.Type;
import client.net.sf.saxon.ce.value.AtomicValue;
import client.net.sf.saxon.ce.value.StringValue;
import client.net.sf.saxon.ce.value.Whitespace;

import java.util.ArrayList;
import java.util.List;


/**
* The XPath id() or element-with-id() function (synonymous for a non-schema-aware processor)
* XPath 2.0 version: accepts any sequence as the first parameter; each item in the sequence
* is taken as an IDREFS value, that is, a space-separated list of ID values.
* Also accepts an optional second argument to identify the target document, this
* defaults to the context node.
*/


public class Id extends SystemFunction {

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

    /**
    * Simplify: add a second implicit argument, the context document
     * @param visitor an expression visitor
     */

     public Expression simplify(ExpressionVisitor visitor) throws XPathException {
        Id id = (Id)super.simplify(visitor);
        if (argument.length == 1) {
            id.addContextDocumentArgument(1, getFunctionName().getLocalName());
        }
        return id;
    }

    /**
     * Type-check the expression. This also calls preEvaluate() to evaluate the function
     * if all the arguments are constant; functions that do not require this behavior
     * can override the preEvaluate method.
     */

    public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException {
        if (argument[1] instanceof RootExpression && contextItemType != null && contextItemType.isAtomicType()) {
            // intercept this to get better diagnostics
            typeError(getFunctionName().getLocalName() +
                    "() function called when the context item is not a node", "XPTY0004", null);
        }
        return super.typeCheck(visitor, contextItemType);
    }

    /**
     * Static analysis: prevent sorting of the argument
     */

    public void checkArguments(ExpressionVisitor visitor) throws XPathException {
        super.checkArguments(visitor);
        Optimizer opt = visitor.getConfiguration().getOptimizer();
        argument[0] = ExpressionTool.unsorted(opt, argument[0], false);
    }

    /**
    * preEvaluate: this method suppresses compile-time evaluation by doing nothing
     * @param visitor an expression visitor
     */

    public Expression preEvaluate(ExpressionVisitor visitor) {
        return this;
    }

    /**
    * Get the static properties of this expression (other than its type). The result is
    * bit-signficant. These properties are used for optimizations. In general, if
    * property bit is set, it is true, but if it is unset, the value is unknown.
     */

    public int computeSpecialProperties() {
        int prop = StaticProperty.ORDERED_NODESET |
                StaticProperty.SINGLE_DOCUMENT_NODESET |
                StaticProperty.NON_CREATIVE;
        if ((getNumberOfArguments() == 1) ||
                (argument[1].getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) {
            prop |= StaticProperty.CONTEXT_DOCUMENT_NODESET;
        }
        return prop;
    }


    /**
    * Evaluate the function to return an iteration of selected nodes.
    */

    public SequenceIterator iterate(XPathContext context) throws XPathException {

        NodeInfo arg1;
        try {
            arg1 = (NodeInfo)argument[1].evaluateItem(context);
        } catch (XPathException e) {
            if (context.getContextItem() instanceof AtomicValue) {
                // Override the unhelpful message that trickles down..
                dynamicError("For the " + getFunctionName().getLocalName() +
                        "() function, the context item is not a node", "XPTY0004", context);
                return null;
            } else {
                throw e;
            }
        }
        arg1 = arg1.getRoot();
        if (arg1.getNodeKind() != Type.DOCUMENT) {
            dynamicError("In the " + getFunctionName().getLocalName() + "() function," +
                            " the tree being searched must be one whose root is a document node", "FODC0001", context);
            return null;
        }
        DocumentInfo doc = (DocumentInfo)arg1;
        SequenceIterator idrefs = argument[0].iterate(context);
        IdMappingFunction map = new IdMappingFunction();
        map.document = doc;
        SequenceIterator result = new MappingIterator(idrefs, map);
        return new DocumentOrderIterator(result, LocalOrderComparer.getInstance());
    }

    private static class IdMappingFunction implements MappingFunction {

        public DocumentInfo document;

        /**
        * Evaluate the function for a single string value
        * (implements the MappingFunction interface)
        */

        public SequenceIterator map(Item item) throws XPathException {

            String idrefs = Whitespace.trim(item.getStringValueCS());

            // If this value contains a space, we need to break it up into its
            // separate tokens; if not, we can process it directly

            if (Whitespace.containsWhitespace(idrefs)) {
                List<StringValue> refs = new ArrayList<StringValue>(10);
                StringTokenizer st = new StringTokenizer(idrefs);
                while (st.hasMoreTokens()) {
                    refs.add(StringValue.makeStringValue(st.nextToken()));
                }
                IdMappingFunction submap = new IdMappingFunction();
                submap.document = document;
                return new MappingIterator(new ListIterator(refs), submap);

            } else {
                return SingletonIterator.makeIterator(document.selectID(idrefs));
            }
        }
    }

}




// 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.Id$IdMappingFunction

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.