Newer
Older
saxon-xslt / src / fr / inist / SaxonXSLT.java
package fr.inist;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import com.saxonica.config.EnterpriseTransformerFactory;

import net.sf.saxon.lib.FeatureKeys;
import net.sf.saxon.lib.Validation;
import net.sf.saxon.trans.XPathException;

public class SaxonXSLT {

    public static void main(String[] args) throws IOException {
	// write your code here
    	
        String source = args[0];
        String style = args[1];
        String output = args[2];
        String schema = args[3];
        File fIn = new File(source);
        File fOut = new File(output);
        File fXslt = new File(style);
        File fSchema = new File(schema);
    	
    	 
        if (style==null) {
            System.out.println("No xslt supplied");
            usage();
            return;
        }
        if (source==null) {
        	System.out.println("No input supplied");
        	usage();
        	return;
        }
        if (output==null) {
        	System.out.println("No output supplied");
        	usage();
            return;
        }
        if (!fOut.isDirectory() || !fOut.exists()) {
        	System.out.println("output must be a valid directory");
        	usage();
            return;
        }
        if (!fIn.exists()) {
        	System.out.println("input must be a valid file or directory");
        	usage();
            return;
        }
        if (!fXslt.exists()) {
        	System.out.println("output must be a valid file");
        	usage();
            return;
        } 
        SaxonXSLT saxonXslt;
        saxonXslt = new SaxonXSLT(fIn, fXslt, fOut);
        if (schema != null) {
        	System.out.println("We will try to validate generated files thanks to "+schema);
        	if (!fSchema.exists()) {
	        	System.out.println("schema must be a valid file");
	        	usage();
	            return;
        	} else {
                saxonXslt.setSchema(fSchema);
                System.out.println("schema : "+fSchema.getAbsolutePath());
                System.out.println("hasSchema() : "+saxonXslt.hasSchema());
                
            }
        }
        saxonXslt.processInput();
    }
    
    public static void usage() {
    	System.out.print("usage : java SaxonXSLT <input> <xslt> <output> [<schema>] (input can be file or dir, output must be a dir)");
    }

    
    private File fIn, fXslt, fOut, fSchema;
    private String outputPath;
    private String inputPath;
    
    
    public SaxonXSLT(File in, File xslt, File out) {
    	this.fIn = in;
    	this.fXslt = xslt;
    	this.fOut = out;
//    	Path outPath = FileSystems.getDefault().getPath(fOut.getAbsolutePath());
    	this.outputPath = fOut.getAbsolutePath();
    	this.inputPath = (fIn.isDirectory()) ? fIn.getAbsolutePath() : fIn.getParentFile().getAbsolutePath();
    	System.out.println("inputPath="+inputPath);
    }
    
    
    public void processInput() throws IOException {
    	this.processNode(fIn);
    }
    
    public void processNode(File node) throws IOException {
    	File[] nodes = node.listFiles();
    	for (File subNode : nodes) {
            if (subNode.isDirectory()) {
            	processNode(subNode);
            } else {
            	Path p = FileSystems.getDefault().getPath(subNode.getAbsolutePath());
            	String contentType = Files.probeContentType(p); 
            	if (subNode.getName().toLowerCase().endsWith(".xml") ||
            		contentType.equalsIgnoreCase("application/xml") ||
            		contentType.equalsIgnoreCase("text/xml") ) {
            		this.apply(subNode);
            	} 
            }
        }
    }
    
    public int apply(File source) {
        try {
            Templates pss = tryCache(fXslt);
            Transformer transformer = pss.newTransformer();
 
            // String path = getServletContext().getRealPath(source);
            File sourceFile = source;
            if (!sourceFile.exists()) {
                throw new XPathException("Source file " + source + " not found");
            }
  
            //deactivation of DTD validation
            XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
            xmlReader.setEntityResolver(new EntityResolver() {
                public InputSource resolveEntity(String pid, String sid) throws SAXException {
                    return new InputSource(new ByteArrayInputStream(new byte[] {}));
                }
            });
            Source xmlSource = new SAXSource(xmlReader, new InputSource(new FileReader(sourceFile)));
 
            String sourceDirPath = source.getParentFile().getAbsolutePath();
            String relativeInputDir = sourceDirPath.substring(inputPath.length());
            File xmlOut = new File(outputPath + File.separator + relativeInputDir, sourceFile.getName());
            
//            System.out.println("transformation de "+source.getAbsolutePath()+" en "+xmlOut.getAbsolutePath());
            
            transformer.transform(xmlSource, new StreamResult(xmlOut));
 
            System.out.println("Transformation OK, consulter le fichier "+xmlOut);
            
            if (hasSchema()) {
            	return validate(xmlOut);
            }
 
        } catch (Exception err) {
        	System.out.println("Transformation KO sur le fichier "+source);
        	System.err.println("Echec XSLT sur le fichier "+source);
            System.err.println(err.getMessage());
            err.printStackTrace();
    		return 1;
        }
		return 0;
    	
    }
    
    
    public int validate(File fileToValidate) {
		try {
			System.setProperty("javax.xml.transform.TransformerFactory",
					"com.saxonica.config.EnterpriseTransformerFactory");
			TransformerFactory factory = TransformerFactory.newInstance();
			factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION, new Integer(
					Validation.STRICT));
			StreamSource schema = new StreamSource(fSchema.toURI().toString());
				((EnterpriseTransformerFactory) factory).addSchema(schema);
			Transformer trans = factory.newTransformer();
			StreamSource source = new StreamSource(fileToValidate.toURI().toString());
			SAXResult sink = new SAXResult(new DefaultHandler());
			trans.transform(source, sink);
			
		} catch (TransformerException err) {
			System.out.println("Validation KO sur le fichier "+fileToValidate.getAbsolutePath());
			System.err.println("Erreur de validation sur le fichier "+fileToValidate.getAbsolutePath());
			System.err.println(err.getMessage());
			return 1;
		}
		System.out.println("Validation OK sur le fichier "+fileToValidate.getAbsolutePath());
		return 0;
    }
    
    
    /**
     * Maintain prepared stylesheets in memory for reuse
     */
  
     private synchronized static Templates tryCache(File xslFile) throws TransformerException {
         // String path = getServletContext().getRealPath(xslPath);
         if (!xslFile.exists()) {
             throw new XPathException("Stylesheet " + xslFile.getAbsolutePath() + " not found");
         }
         String path = xslFile.getAbsolutePath();
  
         Templates x = (Templates)cache.get(path);
         if (x==null) {
             TransformerFactory factory = TransformerFactory.newInstance();
             x = factory.newTemplates(new StreamSource(new File(path)));
             cache.put(path, x);
         }
         return x;
     }
     
     public File getSchema() {
		return fSchema;
	}

	public void setSchema(File fSchema) {
		this.fSchema = fSchema;
	}

	public boolean hasSchema() {
		return (this.fSchema != null);
	}

	private static HashMap<String, Templates> cache = new HashMap<String, Templates>(20);
    
}