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

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

package client.net.sf.saxon.ce.functions;
import client.net.sf.saxon.ce.Configuration;
import client.net.sf.saxon.ce.PreparedStylesheet;
import client.net.sf.saxon.ce.expr.*;
import client.net.sf.saxon.ce.lib.NamespaceConstant;
import client.net.sf.saxon.ce.om.*;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.type.BuiltInAtomicType;
import client.net.sf.saxon.ce.type.SchemaType;
import client.net.sf.saxon.ce.value.AtomicValue;
import client.net.sf.saxon.ce.value.BooleanValue;
import client.net.sf.saxon.ce.value.NumericValue;
import client.net.sf.saxon.ce.value.StringValue;

/**
* This class supports the XSLT element-available and function-available functions.
*/

public class Available extends SystemFunction {

    public Available(int operation) {
        this.operation = operation;
    }

    public Available newInstance() {
        return new Available(operation);
    }

    public static final int ELEMENT_AVAILABLE = 0;
    public static final int FUNCTION_AVAILABLE = 1;
    public static final int TYPE_AVAILABLE = 2;

    private NamespaceResolver nsContext;
    private transient boolean checked = false;



    public void checkArguments(ExpressionVisitor visitor) throws XPathException {
        // the second time checkArguments is called, it's a global check so the static context is inaccurate
        if (checked) {
            return;
        }
        checked = true;
        super.checkArguments(visitor);
        if (!(argument[0] instanceof Literal &&
                (argument.length==1 || argument[1] instanceof Literal))) {
            // we need to save the namespace context
            nsContext = visitor.getStaticContext().getNamespaceResolver();
        }
    }

    /**
    * preEvaluate: this method uses the static context to do early evaluation of the function
    * if the argument is known (which is the normal case)
     * @param visitor the expression visitor
     */

    public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException {
        String lexicalQName = ((Literal)argument[0]).getValue().getStringValue();
        StaticContext env = visitor.getStaticContext();
        boolean b = false;
        Configuration config = visitor.getConfiguration();
        switch(operation) {
            case ELEMENT_AVAILABLE:
                b = env.isElementAvailable(lexicalQName);
                break;
            case FUNCTION_AVAILABLE:
                long arity = -1;
                if (argument.length == 2) {
                    arity = ((NumericValue)argument[1].evaluateItem(env.makeEarlyEvaluationContext())).intValue();
                }
                try {
                    String[] parts = NameChecker.getQNameParts(lexicalQName);
                    String prefix = parts[0];
                    String uri;
                    if (prefix.length() == 0) {
                        uri = env.getDefaultFunctionNamespace();
                    } else {
                        uri = env.getURIForPrefix(prefix);
                    }
                    StructuredQName functionName = new StructuredQName(prefix, uri, parts[1]);
                    b = (env.getFunctionLibrary().hasFunctionSignature(functionName, (int)arity));
                } catch (QNameException e) {
                    XPathException err = new XPathException(e.getMessage());
                    err.setErrorCode("XTDE1400");
                    throw err;
                } catch (XPathException e2) {
                    if ("XTDE0290".equals(e2.getErrorCodeLocalPart())) {
                        e2.setErrorCode("XTDE1400");
                    }
                    throw e2;
                }
                break;
            case TYPE_AVAILABLE:
                try {
                    String[] parts = NameChecker.getQNameParts(lexicalQName);
                    String prefix = parts[0];
                    String uri;
                    if (prefix.length() == 0) {
                        uri = env.getDefaultElementNamespace();
                    } else {
                        uri = env.getURIForPrefix(prefix);
                    }

                    int fingerprint = config.getNamePool().allocate(prefix, uri, parts[1]) & 0xfffff;
                    SchemaType type = config.getSchemaType(fingerprint);
                    b = type instanceof BuiltInAtomicType;
                } catch (QNameException e) {
                    XPathException err = new XPathException(e.getMessage());
                    err.setErrorCode("XTDE1425");
                    throw err;
                }
        }
        return Literal.makeLiteral(BooleanValue.get(b));
    }

    /**
     * Run-time evaluation. This is the only thing in the spec that requires information
     * about in-scope functions to be available at run-time.
    */

    public Item evaluateItem(XPathContext context) throws XPathException {
        AtomicValue av1 = (AtomicValue)argument[0].evaluateItem(context);
        long arity = -1;
        if (argument.length == 2) {
            arity = ((NumericValue)argument[1].evaluateItem(context)).intValue();
        }
        StringValue nameValue = (StringValue)av1;
        String lexicalName = nameValue.getStringValue();
        StructuredQName qName;
        try {
            if (lexicalName.indexOf(':') < 0) {
                // we're in XSLT, where the default namespace for functions can't be changed
                String uri = (operation == FUNCTION_AVAILABLE
                        ? NamespaceConstant.FN
                        : nsContext.getURIForPrefix("", true));
                qName = new StructuredQName("", uri, lexicalName);
            } else {
                qName = StructuredQName.fromLexicalQName(lexicalName,
                    false,
                    nsContext);
            }
        } catch (XPathException e) {
            dynamicError(e.getMessage(), badQNameCode(), context);
            return null;
        }

        boolean b = false;
        switch(operation) {
            case ELEMENT_AVAILABLE:
                b = isElementAvailable(qName.getNamespaceURI(), qName.getLocalName(), context);
                break;
            case FUNCTION_AVAILABLE:
                final FunctionLibrary lib = context.getController().getExecutable().getFunctionLibrary();
                b = (lib.hasFunctionSignature(qName, (int)arity));
                break;
            case TYPE_AVAILABLE:
                final int fp = context.getNamePool().allocate(
                        qName.getPrefix(), qName.getNamespaceURI(), qName.getLocalName()) & 0xfffff;
                SchemaType type = context.getConfiguration().getSchemaType(fp);
                b = (type != null);

        }
        return BooleanValue.get(b);

    }

    private String badQNameCode() {
        switch (operation) {
            case FUNCTION_AVAILABLE:
                return "XTDE1400";
            case TYPE_AVAILABLE:
                return "XTDE1428";
            case ELEMENT_AVAILABLE:
                return "XTDE1440";
            default:
                return null;
        }
    }

    /**
     * Determine at run-time whether a particular instruction is available. Returns true
     * only in the case of XSLT instructions and Saxon extension instructions; returns false
     * for user-defined extension instructions
     * @param uri the namespace URI of the element
     * @param localname the local part of the element name
     * @param context the XPath evaluation context
     * @return true if the instruction is available, in the sense of the XSLT element-available() function
    */

    private boolean isElementAvailable(String uri, String localname, XPathContext context) {

        // This is horribly inefficient. But hopefully it's hardly ever executed, because there
        // is very little point calling element-available() with a dynamically-constructed argument.
        // And the inefficiency is only incurred once, on the first call.

        // Note: this requires the compile-time classes to be available at run-time; it will need
        // changing if we ever want to build a run-time JAR file.

        try {
            PreparedStylesheet pss = (PreparedStylesheet)context.getController().getExecutable();
            return pss.getStyleNodeFactory().isElementAvailable(uri, localname);
        } catch (Exception err) {
            //err.printStackTrace();
            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.Available

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.