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

net.sf.saxon.functions.URIQueryParameters 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.functions;

import net.sf.saxon.Configuration;
import net.sf.saxon.lib.ParseOptions;
import net.sf.saxon.lib.Validation;
import net.sf.saxon.om.AllElementsSpaceStrippingRule;
import net.sf.saxon.om.IgnorableSpaceStrippingRule;
import net.sf.saxon.om.NoElementsSpaceStrippingRule;
import net.sf.saxon.om.SpaceStrippingRule;
import net.sf.saxon.regex.ARegularExpression;
import net.sf.saxon.regex.JavaRegularExpression;
import net.sf.saxon.regex.RegularExpression;
import net.sf.saxon.str.StringView;
import net.sf.saxon.str.UnicodeBuilder;
import net.sf.saxon.trans.Instantiator;
import net.sf.saxon.trans.Maker;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.transpile.CSharpNullable;
import org.xml.sax.XMLReader;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Optional;
import java.util.StringTokenizer;

/**
 * A set of query parameters on a URI passed to the collection() or document() function
 */
@CSharpNullable("enable")
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class URIQueryParameters {

    Optional filter = Optional.empty();
    Optional recurse = Optional.empty();
    Optional validation = Optional.empty();
    Optional strippingRule = Optional.empty();
    Optional onError = Optional.empty();

    Optional xinclude = Optional.empty();
    Optional stable = Optional.empty();
    Optional metadata = Optional.empty();
    Optional contentType = Optional.empty();

    Optional> parserMaker = Optional.empty();


    public static final int ON_ERROR_FAIL = 1;
    public static final int ON_ERROR_WARNING = 2;
    public static final int ON_ERROR_IGNORE = 3;

    /**
     * Create an object representing the query part of a URI
     *
     * @param query  the part of the URI after the "?" symbol
     * @param config the Saxon configuration
     */

    public URIQueryParameters(String query, Configuration config) throws XPathException {
        if (query != null) {
            StringTokenizer t = new StringTokenizer(query, ";&");
            while (t.hasMoreTokens()) {
                String tok = t.nextToken();
                int eq = tok.indexOf('=');
                if (eq > 0 && eq < (tok.length() - 1)) {
                    String keyword = tok.substring(0, eq);
                    String value = tok.substring(eq + 1);
                    processParameter(config, keyword, value);
                }
            }
        }
    }

    private void processParameter(Configuration config, String keyword, String value) throws XPathException {
        if (keyword.equals("select")) {
            filter = Optional.of(makeGlobFilter(value));
        } else if (keyword.equals("match")) {
            ARegularExpression regex = new ARegularExpression(StringView.of(value).tidy(), "", "XP", new ArrayList<>(), config);
            filter = Optional.of(new RegexFilter(regex));
        } else if (keyword.equals("recurse")) {
            recurse = Optional.of("yes".equals(value));
        } else if (keyword.equals("validation")) {
            int v = Validation.getCode(value);
            if (v != Validation.INVALID) {
                validation = Optional.of(v);
            }
        } else if (keyword.equals("strip-space")) {
            switch (value) {
                case "yes":
                    strippingRule = Optional.of(AllElementsSpaceStrippingRule.getInstance());
                    break;
                case "ignorable":
                    strippingRule = Optional.of(IgnorableSpaceStrippingRule.getInstance());
                    break;
                case "no":
                    strippingRule = Optional.of(NoElementsSpaceStrippingRule.getInstance());
                    break;
            }
        } else if (keyword.equals("stable")) {
            if (value.equals("yes")) {
                stable = Optional.of(Boolean.TRUE);
            } else if (value.equals("no")) {
                stable = Optional.of(Boolean.FALSE);
            }
        } else if (keyword.equals("metadata")) {
            if (value.equals("yes")) {
                metadata = Optional.of(Boolean.TRUE);
            } else if (value.equals("no")) {
                metadata = Optional.of(Boolean.FALSE);
            }
        } else if (keyword.equals("xinclude")) {
            if (value.equals("yes")) {
                xinclude = Optional.of(Boolean.TRUE);
            } else if (value.equals("no")) {
                xinclude = Optional.of(Boolean.FALSE);
            }
        } else if (keyword.equals("content-type")) {
            contentType = Optional.of(value);
        } else if (keyword.equals("on-error")) {
            switch (value) {
                case "warning":
                    onError = Optional.of(ON_ERROR_WARNING);
                    break;
                case "ignore":
                    onError = Optional.of(ON_ERROR_IGNORE);
                    break;
                case "fail":
                    onError = Optional.of(ON_ERROR_FAIL);
                    break;
            }
        } else if (keyword.equals("parser") && config != null) {
            parserMaker = Optional.of(new Instantiator<>(value, config));
        }
    }

    public static FilenameFilter makeGlobFilter(String value) throws XPathException {
        UnicodeBuilder sb = new UnicodeBuilder();
        sb.append('^');
        for (int i = 0; i < value.length(); i++) {
            char c = value.charAt(i);
            if (c == '.') {
                // replace "." with "\."
                sb.appendLatin("\\.");
            } else if (c == '*') {
                // replace "*" with ".*"
                sb.appendLatin(".*");
            } else if (c == '?') {
                // replace "?" with ".?"
                sb.appendLatin(".?");
            } else {
                sb.append(c);
            }
        }
        sb.append('$');
        try {
            return new RegexFilter(new JavaRegularExpression(sb.toUnicodeString(), ""));
        } catch (XPathException e) {
            throw new XPathException("Invalid glob " + value + " in collection URI", "FODC0004");
        }
    }

    /**
     * Get the value of the strip-space=yes|no parameter.
     *
     * @return an instance of {@link AllElementsSpaceStrippingRule}, {@link IgnorableSpaceStrippingRule},
     * or {@link NoElementsSpaceStrippingRule}, or absent.
     */

    public Optional getSpaceStrippingRule() {
        return strippingRule;
    }

    /**
     * Get the value of the validation=strict|lax|preserve|strip parameter, or absent if unspecified
     */

    public Optional getValidationMode() {
        return validation;
    }

    /**
     * Get the file name filter (select=pattern), or absent if unspecified
     */

    public Optional getFilenameFilter() {
        return filter;
    }

    /**
     * Get the value of the recurse=yes|no parameter, or absent if unspecified
     */

    public Optional getRecurse() {
        return recurse;
    }

    /**
     * Get the value of the on-error=fail|warning|ignore parameter, or absent if unspecified
     */

    public Optional getOnError() {
        return onError;
    }

    /**
     * Get the value of xinclude=yes|no, or absent if unspecified
     */

    public Optional getXInclude() {
        return xinclude;
    }

    /**
     * Get the value of metadata=yes|no, or absent if unspecified
     */

    public Optional getMetaData() {
        return metadata;
    }

    /**
     * Get the value of media-type, or absent if absent
     */

    public Optional getContentType() {
        return contentType;
    }

    /**
     * Get the value of stable=yes|no, or absent if unspecified
     */

    public Optional getStable() {
        return stable;
    }

    /**
     * Get a factory for the selected XML parser class, or absent if unspecified
     */

    public Optional> getXMLReaderMaker() {
        return parserMaker;
    }

    /**
     * Create ParseOptions based on these query parameters
     */

    @SuppressWarnings("OptionalIsPresent")
    public ParseOptions makeParseOptions(Configuration config) throws XPathException {

        ParseOptions options = new ParseOptions();
        Optional stripSpace = getSpaceStrippingRule();
        if (stripSpace.isPresent()) {
            options = options.withSpaceStrippingRule(stripSpace.get());
        }

        Optional validation = getValidationMode();
        if (validation.isPresent()) {
            options = options.withSchemaValidationMode(validation.get());
        }

        Optional xinclude = getXInclude();
        if (xinclude.isPresent()) {
            options = options.withXIncludeAware(xinclude.get());
        }

        return options;
    }

    /**
     * A FilenameFilter that tests file names against a regular expression
     */

    public static class RegexFilter implements FilenameFilter {

        private final RegularExpression pattern;


        public RegexFilter(RegularExpression regex) {
            this.pattern = regex;
        }

        /**
         * Tests if a specified file should be included in a file list.
         *
         * @param dir  the directory in which the file was found.
         * @param name the name (last component) of the file.
         * @return true if and only if the name should be
         *         included in the file list; false otherwise.
         *         Returns true if the file is a directory or if it matches the glob pattern.
         */

        @Override
        public boolean accept(File dir, String name) {
            return new File(dir, name).isDirectory() || pattern.matches(StringView.of(name).tidy());
        }

        /**
         * Test whether a name matches the pattern (regardless whether it is a directory or not)
         *
         * @param name the name (last component) of the file
         * @return true if the name matches the pattern.
         */
        public boolean matches(String name) {
            return pattern.matches(StringView.of(name).tidy());
        }
    }


}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy