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

org.pageseeder.schematron.ValidatorFactory Maven / Gradle / Ivy

/*
 * Copyright 2015 Allette Systems (Australia)
 * http://www.allette.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ---------- Original copyright notice for this portion of the code ----------
 *
 * Adapted from work by Christophe Lauret and Willy Ekasalim
 *
 * Open Source Initiative OSI - The MIT License:Licensing
 * [OSI Approved License]
 *
 * The MIT License
 *
 * Copyright (c) 2008 Rick Jelliffe, Topologi Pty. Ltd, Allette Systems
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.pageseeder.schematron;

import org.w3c.dom.Document;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

import javax.xml.XMLConstants;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

/**
 * A ValidatorFactory instance can be used to create a Validator object.
 *
 * 

This class uses a fluent style API.

* * @author Christophe Lauret * * @version 2.0 * @since 1.0 */ public final class ValidatorFactory { private static final DebugOutput NO_DEBUG = (systemId) -> null; private static final DebugOutput BASIC_DEBUG = (systemId) -> { String filename = "debug."+removePathExtension(systemId)+".xsl"; return new OutputStreamWriter(new FileOutputStream(filename), StandardCharsets.UTF_8); }; /** * Default XSLT processor. */ private final TransformerFactory _factory; /** * The URI resolver class. */ private final Class _resolver; /** * The error event listener for the ValidatorFactory. */ private final ErrorListener _listener; /** * Indicates where the compiled stylesheets should be saved for debugging. */ private final DebugOutput _debug; /** * Default compile options for this factory. */ private final CompileOptions _options; /** * We keep a shared copy of precompilers (they are thread-safe) */ private static volatile Precompiler precompiler1 = null; private static volatile Precompiler precompiler2 = null; /** * Constructs a new factory. */ public ValidatorFactory() { this(CompileOptions.defaults()); } /** * Constructs a new factory with the specified compile options. */ public ValidatorFactory(CompileOptions options) { this._factory = newSafeTransformerFactory(); this._options = Objects.requireNonNull(options); this._listener = this._factory.getErrorListener(); this._resolver = null; this._debug = NO_DEBUG; } private ValidatorFactory(TransformerFactory factory, CompileOptions options, ErrorListener listener, Class resolver, DebugOutput debug) { this._factory = factory; this._options = Objects.requireNonNull(options); this._listener = Objects.requireNonNull(listener); this._resolver = resolver; this._debug = debug; } public ValidatorFactory options(CompileOptions options) { return new ValidatorFactory(this._factory, options, this._listener, this._resolver, this._debug); } @Deprecated public CompileOptions getOptions() { return this._options; } public CompileOptions options() { return this._options; } /** * Set the error event listener for the ValidatorFactory, which is used for the processing of the * Schematron schema, not for the Schematron validation itself. * * @param listener The error listener. */ public ValidatorFactory errorListener(ErrorListener listener) { return new ValidatorFactory(this._factory, this._options, listener, this._resolver, this._debug); } /** * Get the error event handler for this factory. * * @return The current error handler, which should never be null. */ public ErrorListener getErrorListener() { return this._listener; } /** * Enable debug mode to save a copy of the generated stylesheet to a file for debugging. * *

This method assigned a default DebugOutput implementation. To specify your * own use the {@link #debug(DebugOutput)} method.

* * @return A new factory if debug is not already enabled. */ public ValidatorFactory enableDebug() { // Debug is already enabled if (this._debug != null && this._debug != NO_DEBUG) return this; return new ValidatorFactory(this._factory, this._options, this._listener, this._resolver, BASIC_DEBUG); } /** * Disable debug mode. * * @return A new factory if debug is not already disabled. */ public ValidatorFactory disableDebug() { // Debug is already disabled if (this._debug == null || this._debug == NO_DEBUG) return this; return new ValidatorFactory(this._factory, this._options, this._listener, this._resolver, NO_DEBUG); } /** * Enable debug mode to save a copy of the generated stylesheet when it is generated. * * @return A new factory if debug is not already enabled. */ public ValidatorFactory debug(DebugOutput debug) { return new ValidatorFactory(this._factory, this._options, this._listener, this._resolver, debug); } /** * Set the class name of the resolver to use, overriding built-in Apache resolver */ public ValidatorFactory resolver(Class resolver) { return new ValidatorFactory(this._factory, this._options, this._listener, resolver, this._debug); } /** * Process the specified schema into a Validator object. * * @param schema The Schematron schema to use. * * @return A Validator instance for the specified schema. */ public Validator newValidator(File schema) throws SchematronException { if (!schema.exists()) throw new SchematronException("Unable to find schema", new FileNotFoundException(schema.getPath())); StreamSource source = new StreamSource(schema); return newValidator(source); } /** * Process the specified schema into a Validator object. * * @param schema The Schematron schema to use. * * @return A Validator instance for the specified schema. */ public Validator newValidator(File schema, String phase) throws SchematronException { if (!schema.exists()) throw new SchematronException("Unable to find schema", new FileNotFoundException(schema.getPath())); StreamSource source = new StreamSource(schema); return newValidator(source, phase); } /** * Process the specified schema into a Validator object. * * @param schema The Schematron schema to use. * * @return A Validator instance for the specified schema. * * @throws SchematronException Will wrap any exception occurring while attempting to instantiate a validator. */ public Validator newValidator(Source schema) throws SchematronException { return newValidator(schema, null); } /** * Process the specified schema into a Validator object. * * @param schema The Schematron schema to use. * @param phase The phase for this schema. * * @return A Validator instance for the specified schema. * * @throws SchematronException Will wrap any exception occurring while attempting to instantiate a validator. */ public Validator newValidator(Source schema, String phase) throws SchematronException { Document schematron = this.loadSchema(schema); String systemId = schematron.getDocumentURI(); // Prepare the compiler QueryBinding binding = getQueryBinding(schematron, this._options); Precompiler precompiler = getPrecompiler(binding); Compiler compiler = precompiler.prepare(this._listener, this._options.toParameters(phase)); DOMSource schemaSource = new DOMSource(schematron, systemId); Document stylesheet = compiler.compile(schemaSource); stylesheet.setDocumentURI(systemId); // check debug mode, if true then print the preprocessing results to debug.xslt if (this._debug != null) { try { Writer writer = this._debug.getWriter(systemId); if (writer != null) { StreamResult result = new StreamResult(writer); Transformer transformer = this._factory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, this._debug.indent() ? "yes" : "no"); transformer.transform(new DOMSource(stylesheet), result); } } catch (TransformerException | IOException ex) { throw new SchematronException("Unable to save debug output", ex); } } // Generate the templates from the preprocessing results if (this._resolver != null) { try { this._factory.setURIResolver(this._resolver.newInstance()); } catch (Throwable t) { throw new SchematronException("Unable to instantiate new resolver", t); } } // Generate the validator instance Templates validator; try { validator = this._factory.newTemplates(new DOMSource(stylesheet)); } catch (TransformerException ex) { throw new SchematronException("Unable to generate new Validator from preprocessed "+schema.getSystemId(), ex); } return new Validator(validator); } private Document loadSchema(Source source) throws SchematronException { String systemId = source.getSystemId(); try { DOMResult schema = new DOMResult(); this._factory.newTransformer().transform(source, schema); Document schemaDocument = (Document)schema.getNode(); schemaDocument.setDocumentURI(systemId); return schemaDocument; } catch (TransformerException ex) { throw new SchematronException("Unable to parse source schema", ex); } } private QueryBinding getQueryBinding(Document schematron, CompileOptions options) throws SchematronException { String queryBinding = schematron.getDocumentElement().getAttribute("queryBinding").toLowerCase(); if ("".equals(queryBinding)) { queryBinding = options.defaultQueryBinding(); schematron.getDocumentElement().setAttribute("queryBinding", queryBinding); } return QueryBinding.forValue(queryBinding); } private Precompiler getPrecompiler(QueryBinding binding) throws SchematronException { if ("1.0".equals(binding.version()) && precompiler1 != null) return precompiler1; if ("2.0".equals(binding.version()) && precompiler2 != null) return precompiler2; Precompiler precompiler = Precompiler.create(this._factory, binding); if ("1.0".equals(binding.version())) precompiler1 = precompiler; else if ("2.0".equals(binding.version())) precompiler2 = precompiler; return precompiler; } /** * Given full path to the path and return file name only * * @param filepath full path to a file * @return name of the file only without any of the path */ private static String removePathExtension(String filepath) { String[] split = filepath.split("[/\\\\]"); return split[split.length - 1].replaceAll(".sch$", ""); } private static TransformerFactory newSafeTransformerFactory() { TransformerFactory factory = TransformerFactory.newInstance(); // If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); return factory; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy