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

top.marchand.xml.xsl.doc.AccumulatorStep Maven / Gradle / Ivy

The newest version!
/**
 * 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 https://mozilla.org/MPL/2.0/.
 */
package top.marchand.xml.xsl.doc;

import fr.efl.chaine.xslt.StepJava;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Stack;
import javax.xml.transform.stream.StreamSource;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.io.ReadablePipe;
import com.xmlcalabash.io.WritablePipe;
import com.xmlcalabash.library.DefaultStep;
import com.xmlcalabash.runtime.XAtomicStep;
import net.sf.saxon.Configuration;
import net.sf.saxon.event.PipelineConfiguration;
import net.sf.saxon.event.ProxyReceiver;
import net.sf.saxon.event.Receiver;
import net.sf.saxon.event.Sink;
import net.sf.saxon.expr.parser.Location;
import net.sf.saxon.om.NodeName;
import net.sf.saxon.s9api.Destination;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
import net.sf.saxon.s9api.XdmAtomicValue;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.s9api.XsltTransformer;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.SchemaType;
import net.sf.saxon.type.SimpleType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class accumulates the files that are processed, and on then,
 * is able to generates a entries list as an XML file.
 * 
 * @author cmarchand
 */
public class AccumulatorStep extends StepJava {
    public static final String NS = "top:marchand:xml:xsl:doc";
    private static final Logger LOGGER = LoggerFactory.getLogger(AccumulatorStep.class);
    private static final Stack INPUT_FILES = new Stack<>();
    private static String outputDir;
    private static String absoluteRootFolder;

    String currentInputFile;

    @Override
    public Receiver getReceiver(Configuration c) throws SaxonApiException {
        currentInputFile = getParameter(new QName("input-absolute")).toString();
        outputDir = getParameter(new QName("outputFolder")).toString();
        absoluteRootFolder = getParameter(new QName("absoluteRootFolder")).toString();
        return new AccumulatorStepReceiver(getNextReceiver(c));
    }
    
    class AccumulatorStepReceiver extends ProxyReceiver {
        private final Stack stack;
        private String currentElementName;

        public AccumulatorStepReceiver(Receiver nextReceiver) {
            super(nextReceiver);
            stack = new Stack<>();
        }

        @Override
        public void startElement(NodeName elemName, SchemaType typeCode, Location location, int properties) throws XPathException {
            super.startElement(elemName, typeCode, location, properties);
            currentElementName = elemName.getLocalPart();
            stack.push(elemName);
            if("file".equals(currentElementName)) {
                if(stack.size()==1) {
                    INPUT_FILES.push(new Triple(currentInputFile, null, absoluteRootFolder));
                }
            }
        }

        @Override
        public void endElement() throws XPathException {
            super.endElement();
            stack.pop();
        }

        @Override
        public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, Location locationId, int properties) throws XPathException {
            super.attribute(nameCode, typeCode, value, locationId, properties);
            if("file".equals(currentElementName)) {
                if(stack.size()==1) {
                    if(nameCode.getLocalPart().equals("welcomeOutputUri")) {
                        LOGGER.debug("setting targetUri="+value.toString());
                        INPUT_FILES.peek().targetUri = value.toString();
                    } else if(nameCode.getLocalPart().equals("levelsToKeep")) {
                        INPUT_FILES.peek().levelsToKeep = Integer.parseInt(value.toString());
                    } else if(nameCode.getLocalPart().equals("index-label")) {
                        INPUT_FILES.peek().label = value.toString();
                    }
                }
            }
        }
    }
    /**
     * Generates the index File
     * @param projectName
     * @return The generated index file, or null if it was impossible to generate it.
     * @throws IOException
     * @throws SaxonApiException
     * @throws URISyntaxException 
     */
    static File generateIndex(String projectName) throws IOException, SaxonApiException, URISyntaxException {
        // we do not work with absolute anymore, only relatives
        if(outputDir!=null) {
            String outputPath = new File(new URI(outputDir)).getAbsolutePath();
            StringBuilder sb = new StringBuilder();
            for(Triple triple:INPUT_FILES) {
                LOGGER.debug(triple.toString());
                String targetReadUri = new File(new URI(triple.targetUri)).getAbsolutePath();
                String targetUri = targetReadUri.subSequence(outputPath.length()+1, targetReadUri.length()).toString();
                String sourceUri = triple.label;
                sb.append(sourceUri).append("@").append(targetUri).append("@").append(triple.levelsToKeep).append("|");
            }
            String data = sb.deleteCharAt(sb.length()-1).toString();
            LOGGER.debug("data="+data);
            Processor proc = new Processor(Configuration.newConfiguration());
            XsltExecutable exec = proc.newXsltCompiler().compile(new StreamSource(new URL("cp:/generateWholeIndex.xsl").openStream()));
            XsltTransformer transformer = exec.load();
            transformer.setInitialTemplate(new QName(NS,"main"));
            transformer.setParameter(new QName(NS,"programName"), new XdmAtomicValue(projectName));
            transformer.setParameter(new QName(NS, "absoluteRootDir"), new XdmAtomicValue(absoluteRootFolder));
            transformer.setParameter(new QName(NS, "sData"), new XdmAtomicValue(data));
            File ret = new File(new File(outputPath), "entries.xml");
            Serializer serializer = proc.newSerializer(ret);
            transformer.setDestination(serializer);
            transformer.transform();
            return ret;
        } else {
            // here there was nothing to generate, so returns null
            return null;
        }
    }
    
    private static class Triple {
        String label;
        String targetUri;
        String absoluteRootPath;
        int levelsToKeep;
        
        Triple(String label, String targetUri, String absoluteRootPath) {
            super();
            this.label=label;
            this.targetUri=targetUri;
            this.absoluteRootPath=absoluteRootPath;
        }

        @Override
        public String toString() {
            return "label="+label+"\ntargetUri="+targetUri+"\nabsoluteRootFolder="+absoluteRootFolder;
        }
        
        
    }
    
    public static class CalabashStep extends DefaultStep {
        
        public CalabashStep(XProcRuntime runtime, XAtomicStep step) {
            super(runtime, step);
        }
        
        private static final QName _absoluteRootFolder = new QName("absoluteRootFolder");
        
        private ReadablePipe source = null;
        private WritablePipe result = null;
        
        public void setInput(String port, ReadablePipe pipe) {
            source = pipe;
        }
        
        public void setOutput(String port, WritablePipe pipe) {
            result = pipe;
        }
        
        public void reset() {
            source.resetReader();
            result.resetWriter();
        }
        
        public void run() throws SaxonApiException {
            super.run();
            try {
                absoluteRootFolder = getOption(_absoluteRootFolder).getString();
                while (source.moreDocuments()) {
                    final XdmNode doc = source.read();
                    Configuration configuration = runtime.getConfiguration().getProcessor().getUnderlyingConfiguration();
                    final Receiver accumulator = new AccumulatorStep() {{
                        currentInputFile = doc.getBaseURI().toASCIIString();
                    }}.new AccumulatorStepReceiver(new Sink(new PipelineConfiguration(configuration)));
                    XsltTransformer identity = new Processor(configuration)
                        .newXsltCompiler()
                        .compile(new StreamSource(new URL("cp:/lib/identity.xsl").openStream()))
                        .load();
                    identity.setInitialContextNode(doc);
                    identity.setDestination(new Destination() {
                            public void close() {}
                            public Receiver getReceiver(Configuration c) { return accumulator; }
                        });
                    identity.transform();
                    result.write(doc);
                }
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    }
    
    public static class GenerateIndexStep extends DefaultStep {
        
        public GenerateIndexStep(XProcRuntime runtime, XAtomicStep step) {
            super(runtime, step);
        }
        
        private static final QName _projectName = new QName("projectName");
        private static final QName _outputFolder = new QName("outputFolder");
        
        public void reset() {}
        
        public void run() throws SaxonApiException {
            super.run();
            try {
                outputDir = getOption(_outputFolder).getString();
                File indexFile = generateIndex(getOption(_projectName).getString());
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy