All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.style.XSLAcceptExpose Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.style;

import net.sf.saxon.om.*;
import net.sf.saxon.pattern.*;
import net.sf.saxon.trans.ComponentTest;
import net.sf.saxon.trans.Visibility;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
import net.sf.saxon.value.Whitespace;

import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * Handler for xsl:accept and xsl:expose elements in stylesheet.
 */
public abstract class XSLAcceptExpose extends StyleElement {

    private final Set explicitComponentTests = new HashSet<>();
    private final Set wildcardComponentTests = new HashSet<>();
    private Visibility visibility = Visibility.UNDEFINED;

    @Override
    public Visibility getVisibility() {
        return visibility;
    }

    public Set getExplicitComponentTests() throws XPathException {
        prepareAttributes();
        return explicitComponentTests;
    }

    public Set getWildcardComponentTests() {
        prepareAttributes();
        return wildcardComponentTests;
    }

    @Override
    protected void prepareAttributes() {

        if (visibility != Visibility.UNDEFINED) {
            return;
        }

        String componentAtt = null;
        String namesAtt = null;
        String visibilityAtt = null;

        for (AttributeInfo att : attributes()) {
            NodeName attName = att.getNodeName();
            String f = attName.getDisplayName();
            String value = att.getValue();
            switch (f) {
                case "names":
                    namesAtt = Whitespace.trim(value);
                    break;
                case "component":
                    componentAtt = Whitespace.trim(value);
                    break;
                case "visibility":
                    visibilityAtt = Whitespace.trim(value);
                    break;
                default:
                    checkUnknownAttribute(attName);
                    break;
            }
        }

        if (visibilityAtt == null) {
            reportAbsence("visibility");
            visibility = Visibility.PRIVATE;
        } else {
            visibility = interpretVisibilityValue(visibilityAtt, this instanceof XSLAccept ? "ha" : "");
            if (visibility == Visibility.UNDEFINED) {
                visibility = Visibility.PRIVATE; // fall back in case of errors
            }
        }


        int componentTypeCode = StandardNames.XSL_FUNCTION;
        if (componentAtt == null) {
            reportAbsence("component");
        } else {
            String local = Whitespace.trim(componentAtt);
            switch (local) {
                case "function":
                    componentTypeCode = StandardNames.XSL_FUNCTION;
                    break;
                case "template":
                    componentTypeCode = StandardNames.XSL_TEMPLATE;
                    break;
                case "variable":
                    componentTypeCode = StandardNames.XSL_VARIABLE;
                    break;
                case "attribute-set":
                    componentTypeCode = StandardNames.XSL_ATTRIBUTE_SET;
                    break;
                case "mode":
                    componentTypeCode = StandardNames.XSL_MODE;
                    break;
                case "*":
                    // spec change bug 29478
                    componentTypeCode = -1;
                    break;
                default:
                    compileError("The component type is not one of the allowed names (function, template, variable, attribute-set, or mode)",
                                 "XTSE0020");
                    return;
            }
        }

        if (namesAtt == null) {
            reportAbsence("names");
            namesAtt = "";
        }
        StringTokenizer st = new StringTokenizer(namesAtt, " \t\r\n");
        while (st.hasMoreTokens()) {
            final String tok = st.nextToken();
            QNameTest test;
            int hash = tok.lastIndexOf('#');
            if (hash > 0 && tok.indexOf('}', hash) < 0) {   // ignore any '#' within a namespace URI of an EQName
                if (componentTypeCode == -1) {
                    compileErrorInAttribute("When component='*' is specified, all names must be wildcards",
                                 this instanceof XSLAccept ? "XTSE3032" : "XTSE3022", "names");
                } else if (componentTypeCode == StandardNames.XSL_FUNCTION) {
                    StructuredQName name = makeQName(tok.substring(0, hash), null, "names");
                    test = new NameTest(Type.ELEMENT, name.getNamespaceUri(), name.getLocalPart(), getNamePool());
                    int arity = 0;
                    try {
                        arity = Integer.parseInt(tok.substring(hash + 1));
                    } catch (NumberFormatException err) {
                        compileErrorInAttribute("Malformed function arity in '" + tok + "'", "XTSE0020", "names");
                    }
                    explicitComponentTests.add(new ComponentTest(componentTypeCode, test, arity));
                } else {
                    compileErrorInAttribute("Cannot specify arity for components other than functions", "XTSE3020", "names");
                }
            } else if (tok.equals("*")) {
                test = AnyNodeTest.getInstance();
                addWildCardTest(componentTypeCode, test);
            } else if (tok.endsWith(":*")) {
                if (tok.length() == 2) {
                    compileErrorInAttribute("No prefix before ':*'", "XTSE0020", "names");
                }
                String prefix = tok.substring(0, tok.length() - 2);
                NamespaceUri uri = getURIForPrefix(prefix, false);
                if (uri == null) {
                    compileErrorInAttribute("Undeclared prefix " + prefix, "XTSE0020", "names");
                    uri = NamespaceUri.ANONYMOUS; // for recovery
                }
                test = new NamespaceTest(getNamePool(), Type.ELEMENT, uri);
                addWildCardTest(componentTypeCode, test);
            } else if (tok.startsWith("Q{") && tok.endsWith("}*")) {
                final String uri = tok.substring(2, tok.length() - 2);
                test = new NamespaceTest(getNamePool(), Type.ELEMENT, NamespaceUri.of(uri));
                wildcardComponentTests.add(new ComponentTest(componentTypeCode, test, -1));
            } else if (tok.startsWith("*:")) {
                if (tok.length() == 2) {
                    compileErrorInAttribute("No local name after '*:'", "XTSE0020", "names");
                }
                final String localname = tok.substring(2);
                test = new LocalNameTest(getNamePool(), Type.ELEMENT, localname);
                addWildCardTest(componentTypeCode, test);

            } else {
                if (componentTypeCode == -1) {
                    compileErrorInAttribute("When component='*' is specified, all names must be wildcards",
                                 this instanceof XSLAccept ? "XTSE3032" : "XTSE3022", "names");
                } else if (componentTypeCode == StandardNames.XSL_FUNCTION) {
                    compileErrorInAttribute("When the name identifies a function, the arity must be given (XSLT 3.0 erratum E36)",
                                            "XTSE3020", "names");

                } else {
                    StructuredQName name = makeQName(tok, null, "names");
                    test = new NameTest(Type.ELEMENT, name.getNamespaceUri(), name.getLocalPart(), getNamePool());
                    explicitComponentTests.add(new ComponentTest(componentTypeCode, test, -1));
                }
            }

        }
    }

    private void addWildCardTest(int componentTypeCode, QNameTest test) {
        if (componentTypeCode == -1) {
            wildcardComponentTests.add(new ComponentTest(StandardNames.XSL_FUNCTION, test, -1));
            wildcardComponentTests.add(new ComponentTest(StandardNames.XSL_TEMPLATE, test, -1));
            wildcardComponentTests.add(new ComponentTest(StandardNames.XSL_VARIABLE, test, -1));
            wildcardComponentTests.add(new ComponentTest(StandardNames.XSL_ATTRIBUTE_SET, test, -1));
            wildcardComponentTests.add(new ComponentTest(StandardNames.XSL_MODE, test, -1));
        } else {
            wildcardComponentTests.add(new ComponentTest(componentTypeCode, test, -1));
        }
    }




}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy