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

gov.nasa.pds.tools.label.SchematronTransformer Maven / Gradle / Ivy

// Copyright 2009-2018, by the California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship acknowledged.
// Any commercial use must be negotiated with the Office of Technology
// Transfer at the California Institute of Technology.
//
// This software is subject to U. S. export control laws and regulations
// (22 C.F.R. 120-130 and 15 C.F.R. 730-774). To the extent that the software
// is subject to U.S. export control laws and regulations, the recipient has
// the responsibility to obtain export licenses or other export authority as
// may be required before exporting such information to foreign countries or
// providing access to foreign nationals.
//
// $Id$
package gov.nasa.pds.tools.label;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import gov.nasa.pds.tools.util.Utility;
import gov.nasa.pds.tools.util.XslURIResolver;
import gov.nasa.pds.tools.validate.ProblemDefinition;
import gov.nasa.pds.tools.validate.ProblemHandler;
import gov.nasa.pds.tools.validate.ProblemType;
import gov.nasa.pds.tools.validate.ValidationProblem;

/**
 * A class that transforms Schematron files based on the isoSchematron stylesheet.
 *
 * @author mcayanan
 *
 */
public class SchematronTransformer {
  private static final Logger LOG = LoggerFactory.getLogger(SchematronTransformer.class);
  private Transformer isoTransformer;
  private TransformerFactory transformerFactory;
  private Map cachedTransformers;

  /**
   * Constructor.
   *
   * @throws TransformerConfigurationException A transformer configuration error occurred.
   */
  public SchematronTransformer() throws TransformerConfigurationException {
    // Use saxon for schematron (i.e. the XSLT generation).
    System.setProperty("javax.xml.transform.TransformerFactory",
        "net.sf.saxon.TransformerFactoryImpl");
    DocumentBuilderFactory.newInstance().setNamespaceAware(true);
    TransformerFactory isoFactory = TransformerFactory.newInstance();
    // Set the resolver that will look in the jar for imports
    isoFactory.setURIResolver(new XslURIResolver());
    // Load the isoSchematron stylesheet that will be used to transform each
    // schematron file
    Source isoSchematron = new StreamSource(
        LabelValidator.class.getResourceAsStream("/schematron/iso_svrl_for_xslt2.xsl"));
    isoTransformer = isoFactory.newTransformer(isoSchematron);
    transformerFactory = TransformerFactory.newInstance();
    cachedTransformers = new HashMap();
  }

  /**
   * Transform the given schematron source.
   *
   * @param source The schematron source.
   *
   * @return A transformed schematron.
   *
   * @throws TransformerException If an error occurred during the transform process.
   */
  public Transformer transform(Source source) throws TransformerException {
    return transform(source, null);
  }

  /**
   * Transform the given schematron source.
   *
   * @param source The schematron source.
   * @param handler Container to hold problems that occurred during the transform process.
   *
   * @return A transformed schematron.
   *
   * @throws TransformerException If an error occurred during the transform process.
   */
  public Transformer transform(Source source, ProblemHandler handler) throws TransformerException {
    Transformer transformer = null;
    if (cachedTransformers.containsKey(source.getSystemId())) {
      transformer = cachedTransformers.get(source.getSystemId());
    } else {
      if (handler != null) {
        isoTransformer.setErrorListener(new TransformerErrorListener(handler));
      }
      StringWriter schematronStyleSheet = new StringWriter();
      isoTransformer.transform(source, new StreamResult(schematronStyleSheet));
      transformer = transformerFactory
          .newTransformer(new StreamSource(new StringReader(schematronStyleSheet.toString())));
    }
    return transformer;
  }

  /**
   * Transform the given schematron.
   *
   * @param schematron The URL to the schematron.
   *
   * @return A transformed schematron.
   *
   * @throws TransformerException If an error occurred during the transform process.
   */
  public Transformer transform(URL schematron) throws TransformerException {
    return transform(schematron, null);
  }

  /**
   * Transform the given schematron.
   *
   * @param schematron the URL to the schematron.
   * @param handler an problem handler to capture problems.
   *
   * @return a transformed schematron.
   *
   * @throws TransformerException if an error occurred during the transform process.
   */
  public Transformer transform(URL schematron, ProblemHandler handler) throws TransformerException {
    Transformer transformer = null;
    LOG.debug("transform:schematron {}", schematron);

    if (cachedTransformers.containsKey(schematron.toString())) {
      transformer = cachedTransformers.get(schematron.toString());
    } else {
      if (handler != null) {
        isoTransformer.setErrorListener(new TransformerErrorListener(handler));
      }
      StringWriter schematronStyleSheet = new StringWriter();
      InputStream in = null;
      URLConnection conn = null;
      try {
        conn = schematron.openConnection();
        in = Utility.openConnection(conn);

        StreamSource source = new StreamSource(in);
        /* This fixes the problem but is it a good fix. The message now indicates that it is finding
         * the same URI (systemId) for two files. The one it is reading and the source that we have?
         * Maybe in saxon 12.3 it fills in the systemId correctly? Cannot find anything that makes
         * this fix definitive good or bad but that is a search skill problem not lack of information
         * 
         * source.setSystemId(schematron.toString()); */
        isoTransformer.transform(source, new StreamResult(schematronStyleSheet));
        transformer = transformerFactory
            .newTransformer(new StreamSource(new StringReader(schematronStyleSheet.toString())));
      } catch (TransformerException te) {
        // Only throw problem if a handler was not set.
        if (handler == null) {
          throw te;
        }
      } catch (IOException io) {
        String message = "";
        if (io instanceof FileNotFoundException) {
          message = "Cannot read schematron as URL cannot be found: " + io.getMessage();
        } else {
          // message = io.getMessage();
          // Put a more detail message since io.getMessage only return the schematron file
          // name.
          message = "Cannot read schematron from URL " + schematron;
        }
        LOG.debug("transform:message {}", message);
        if (handler == null) {
          throw new TransformerException(message);
        }
        handler.addProblem(new ValidationProblem(
            new ProblemDefinition(ExceptionType.FATAL, ProblemType.SCHEMATRON_ERROR, message),
            schematron));
      } finally {
        IOUtils.closeQuietly(in);
        IOUtils.close(conn);
      }
    }
    return transformer;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy