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

com.xmlcalabash.runtime.XUntilUnchanged Maven / Gradle / Ivy

The newest version!
package com.xmlcalabash.runtime;

import com.xmlcalabash.core.XProcData;
import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.io.Pipe;
import com.xmlcalabash.io.ReadablePipe;
import com.xmlcalabash.io.ReadOnlyPipe;
import com.xmlcalabash.io.WritablePipe;
import com.xmlcalabash.model.RuntimeValue;
import com.xmlcalabash.model.Step;
import com.xmlcalabash.model.Variable;
import com.xmlcalabash.util.MessageFormatter;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XPathCompiler;
import net.sf.saxon.s9api.XPathExecutable;
import net.sf.saxon.s9api.XPathSelector;
import net.sf.saxon.s9api.XdmAtomicValue;
import net.sf.saxon.s9api.XdmItem;
import net.sf.saxon.s9api.XdmNode;

import java.util.Iterator;
import java.util.Vector;

/**
 * Created by IntelliJ IDEA.
 * User: ndw
 * Date: Oct 14, 2008
 * Time: 5:44:42 AM
 * To change this template use File | Settings | File Templates.
 */
public class XUntilUnchanged extends XCompoundStep {
    private static final QName doca = new QName("","doca");
    private static final QName docb = new QName("","docb");

    private Pipe current = null;
    private int sequencePosition = 0;
    private int sequenceLength = 0;

    public XUntilUnchanged(XProcRuntime runtime, Step step, XCompoundStep parent) {
        super(runtime, step, parent);
    }

    public ReadablePipe getBinding(String stepName, String portName) {
        if (name.equals(stepName) && ("#current".equals(portName) || "current".equals(portName))) {
            if (current == null) {
                current = new Pipe(runtime);
            }
            return new ReadOnlyPipe(runtime, current.documents());
        } else {
            return super.getBinding(stepName, portName);
        }
    }

    protected void copyInputs() throws SaxonApiException {
        // nop;
    }

    public void reset() {
        super.reset();
        sequenceLength = 0;
        sequencePosition = 0;
    }

    protected void doRun() throws SaxonApiException {
        logger.trace("Running cx:until-unchanged " + step.getName());

        XProcData data = runtime.getXProcData();
        data.openFrame(this);

        if (current == null) {
            current = new Pipe(runtime);
        }

        String iport = "#iteration-source";

        sequencePosition = 0;
        sequenceLength = 1;

        inScopeOptions = parent.getInScopeOptions();

        runtime.getXProcData().setIterationSize(sequenceLength);

        String iPortName = null;
        String oPortName = null;
        for (String port : inputs.keySet()) {
            if (port.startsWith("|")) {
                iPortName = port;
                oPortName = port.substring(1);
            }
        }

        runtime.start(this);

        try {
            for (ReadablePipe is_reader : inputs.get(iport)) {
                XdmNode os_doc = null;

                while (is_reader.moreDocuments()) {
                    XdmNode is_doc = is_reader.read();
                    boolean changed = true;

                    while (changed) {
                        // Setup the current port before we compute variables!
                        current.resetWriter();
                        current.write(is_doc);
                        logger.trace(MessageFormatter.nodeMessage(step.getNode(), "Copy to current"));

                        sequencePosition++;
                        runtime.getXProcData().setIterationPosition(sequencePosition);

                        for (Variable var : step.getVariables()) {
                            RuntimeValue value = computeValue(var);
                            inScopeOptions.put(var.getName(), value);
                        }

                        // N.B. At this time, there are no compound steps that accept parameters or options,
                        // so the order in which we calculate them doesn't matter. That will change if/when
                        // there are such compound steps.

                        // Calculate all the variables
                        inScopeOptions = parent.getInScopeOptions();
                        for (Variable var : step.getVariables()) {
                            RuntimeValue value = computeValue(var);
                            inScopeOptions.put(var.getName(), value);
                        }

                        for (XStep step : subpipeline) {
                            step.run();
                        }

                        int docsCopied = 0;

                        for (ReadablePipe reader : inputs.get(iPortName)) {
                            while (reader.moreDocuments()) {
                                os_doc = reader.read();
                                docsCopied++;
                            }
                            reader.resetReader();
                        }

                        if (docsCopied != 1) {
                            throw XProcException.dynamicError(6, "Writing to " + iPortName + " on " + getStep().getName());
                        }

                        for (XStep step : subpipeline) {
                            step.reset();
                        }

                        XPathCompiler xcomp = runtime.getProcessor().newXPathCompiler();
                        xcomp.declareVariable(doca);
                        xcomp.declareVariable(docb);

                        XPathExecutable xexec = xcomp.compile("deep-equal($doca,$docb)");
                        XPathSelector selector = xexec.load();

                        selector.setVariable(doca, is_doc);
                        selector.setVariable(docb, os_doc);

                        Iterator values = selector.iterator();
                        XdmAtomicValue item = (XdmAtomicValue) values.next();
                        changed = !item.getBooleanValue();

                        is_doc = os_doc;
                    }

                    WritablePipe pipe = outputs.get(oPortName);
                    pipe.write(os_doc);
                }
            }

        } finally {
            for (String port : inputs.keySet()) {
                if (port.startsWith("|")) {
                    String wport = port.substring(1);
                    WritablePipe pipe = outputs.get(wport);
                    pipe.close(); // Indicate that we're done
                }
            }
            runtime.finish(this);
            data.closeFrame();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy