/** * $Id: $ * $Date: $ * */ package org.xmlsh.calabash; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import javax.xml.transform.stream.StreamSource; import net.sf.saxon.event.ComplexContentOutputter; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.TreeReceiver; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.s9api.Destination; import net.sf.saxon.s9api.DocumentBuilder; import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.QName; import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.XQueryCompiler; import net.sf.saxon.s9api.XQueryEvaluator; import net.sf.saxon.s9api.XQueryExecutable; import net.sf.saxon.s9api.XdmItem; import net.sf.saxon.s9api.XdmNode; import net.sf.saxon.s9api.XdmValue; import net.sf.saxon.trans.XPathException; import org.xmlsh.core.CoreException; import org.xmlsh.core.InputPort; import org.xmlsh.core.NamedPort; import org.xmlsh.core.Options; import org.xmlsh.core.OutputPort; import org.xmlsh.core.XCommand; import org.xmlsh.core.XValue; import org.xmlsh.core.Options.OptionValue; import org.xmlsh.util.Util; import com.xmlcalabash.core.XProcConfiguration; import com.xmlcalabash.core.XProcException; import com.xmlcalabash.core.XProcRuntime; import com.xmlcalabash.io.ReadablePipe; import com.xmlcalabash.model.RuntimeValue; import com.xmlcalabash.runtime.XPipeline; public class xproc extends XCommand { private XProcRuntime runtime = null; @Override public int run(List<XValue> args) throws Exception { /** * DAL: Note can NOT share processor with Calabash, it does global things to it * which are incompatible and not thread safe */ XProcConfiguration config = new XProcConfiguration(false); runtime = new XProcRuntime(config); // runtime.setPhoneHome(false); Processor proc = config.getProcessor(); DocumentBuilder builder = proc.newDocumentBuilder(); Hashtable<String,Vector<XdmNode>> inputs = new Hashtable<String,Vector<XdmNode>>(); Hashtable<QName, String> parameters = new Hashtable<QName,String>(); Hashtable<QName, String> options = new Hashtable<QName,String>(); Options opts = new Options("b=base:,n,iw=iwrap,ow=owrap,o=option:+"); opts.parse(args); args = opts.getRemainingArgs(); boolean noInput = opts.hasOpt("n"); String base = opts.getOptString("b", null); if( args.size() != 1 ) usage(); InputStream ins = getInput( args.get(0)).asInputStream(getSerializeOpts()); XdmNode spec = builder.build(new StreamSource(ins)); ins.close(); if( base != null ) spec.getUnderlyingNode().setSystemId(base); boolean iwrap = opts.hasOpt("iw"); boolean owrap = opts.hasOpt("ow"); OptionValue ovs = opts.getOpt("o"); if( ovs != null ){ for( XValue v : ovs.getValues() ){ String value = v.toString(); String[] namevalue = value.split("="); if( namevalue.length != 2 ) usage(); options.put(new QName(namevalue[0]), namevalue[1]); } } if( ! noInput ){ InputStream in = getStdin().asInputStream(getSerializeOpts()); XdmNode root = builder.build(new StreamSource(in)); Vector<XdmNode> sources = getSources( root , iwrap ); inputs.put("source", sources ); } for( NamedPort<InputPort> input : getEnv().getInputPorts() ){ String name = input.getName(); if( ! Util.isBlank(name) && ! "input".equals(name)){ InputStream in = input.getPort().asInputStream(getSerializeOpts()); XdmNode root = builder.build(new StreamSource(in)); Vector<XdmNode> sources = getSources( root , iwrap ); inputs.put( name , sources ); } } Hashtable<String,ReadablePipe> results = runPipe(spec, inputs, parameters, options ); writeResults(results,owrap); return 0; } /* * Get the sources, optionally unwrapping from root document * */ private Vector<XdmNode> getSources(XdmNode root, boolean iwrap) throws SaxonApiException { Vector<XdmNode> sources = new Vector<XdmNode>(); if( ! iwrap ){ sources.add( root ); return sources; } // wrap each sub-node in a document XQueryCompiler compiler = runtime.getProcessor().newXQueryCompiler(); XQueryExecutable exec = compiler.compile( "for $node in /*/* return document { $node } " ); XQueryEvaluator eval = exec.load(); eval.setContextItem( root ); for( XdmItem item : eval ){ if( item instanceof XdmNode ) sources.add( (XdmNode) item ); } return sources; } private void writeResults(Hashtable<String, ReadablePipe> results, boolean owrap ) throws SaxonApiException, CoreException, IOException { ReadablePipe pipe = results.get("result"); if( pipe != null ) writeResult(pipe, getStdout(),owrap); for( String portname : results.keySet() ){ if( portname.equals("result")) continue; if( portname.equals("error")){ writeResult( results.get(portname), getStderr(),false); continue ; } OutputPort out = getEnv().getOutputPort( portname ); if( out != null ) writeResult( results.get(portname) , out,owrap ); } } private void writeResult(ReadablePipe pipe,OutputPort port, boolean owrap) throws SaxonApiException, CoreException,IOException { XdmNode result = null; if( owrap ) result = wrapResult( pipe ); else result = pipe.read(); /* Destination out = port.asDestination(getSerializeOpts()); writeXdmValue(result, out); */ Processor qtproc = runtime.getProcessor(); XQueryCompiler xqcomp = qtproc.newXQueryCompiler(); XQueryExecutable xqexec = xqcomp.compile("."); XQueryEvaluator xqeval = xqexec.load(); xqeval.setContextItem(result); // Serializer serializer = new Serializer(); // serializer.setOutputStream(port.asOutputStream()); xqeval.setDestination(port.asDestination(getSerializeOpts())); xqeval.run(); /* XPathCompiler compiler = runtime.getProcessor().newXPathCompiler(); XPathExecutable exec = compiler.compile( "/document/title" ); XPathSelector eval = exec.load(); eval.setContextItem( result ); XdmValue v = eval.evaluate(); NodeInfo info = (NodeInfo) v.getUnderlyingValue(); TinyTree.diagnosticDump(info); */ /* Destination out = port.asDestination(getSerializeOpts()); runtime.getProcessor().writeXdmValue(result, out); */ /* Destination out = port.asDestination(getSerializeOpts()); writeXdmValue(result, out); */ } private XdmNode wrapResult(ReadablePipe pipe) throws SaxonApiException { ArrayList<XdmItem> list = new ArrayList<XdmItem>(); do { list.add(pipe.read()); } while( pipe.moreDocuments()); XdmValue docs = new XdmValue( list ); Processor qtproc = runtime.getProcessor(); XQueryCompiler xqcomp = qtproc.newXQueryCompiler(); XQueryExecutable xqexec = xqcomp.compile("declare variable $docs external; <wrap>{$docs}</wrap>"); XQueryEvaluator xqeval = xqexec.load(); xqeval.setExternalVariable(new QName("docs"), docs ); return (XdmNode) xqeval.evaluate(); } public void writeXdmValue(XdmValue value, Destination destination) throws SaxonApiException { try { Receiver out = destination.getReceiver(runtime.getProcessor().getUnderlyingConfiguration()); ComplexContentOutputter out2 = new ComplexContentOutputter(runtime.getProcessor().getUnderlyingConfiguration().makePipelineConfiguration()); out2.setReceiver(out); TreeReceiver tree = new TreeReceiver(out2); tree.open(); tree.startDocument(0); for (Iterator<XdmItem> it = value.iterator(); it.hasNext();) { XdmItem item = it.next(); tree.append((Item)item.getUnderlyingValue(), 0, NodeInfo.ALL_NAMESPACES ); // NodeInfo.NO_NAMESPACES );//NodeInfo.LOCAL_NAMESPACES ); // NodeInfo.LOCAL_NAMESPACES ); // NodeInfo.NO_NAMESPACES);//NodeInfo.ALL_NAMESPACES); } tree.endDocument(); tree.close(); } catch (XPathException err) { throw new SaxonApiException(err); } } /** * DAL: Note: * This method (runPipe) was copied from the calabash source RunTestReport.java with explicit permission of the author, Norman Walsh. * * @param pipeline * @param inputs * @param outputs * @param parameters * @param options * @return * @throws SaxonApiException */ private Hashtable<String,ReadablePipe> runPipe(XdmNode pipeline, Hashtable<String, Vector<XdmNode>> inputs, // Hashtable<String, Vector<XdmNode>> outputs, Hashtable<QName, String> parameters, Hashtable<QName, String> options) throws SaxonApiException { XPipeline xpipeline = runtime.use(pipeline); if (inputs != null) { for (String port : inputs.keySet()) { xpipeline.clearInputs(port); for (XdmNode node : inputs.get(port)) { xpipeline.writeTo(port, node); } } } if (parameters != null) { for (QName name : parameters.keySet()) { xpipeline.setParameter(name, new RuntimeValue(parameters.get(name))); } } if (options != null) { for (QName name : options.keySet()) { // HACK HACK HACK! RuntimeValue v; v = new RuntimeValue(options.get(name)); xpipeline.passOption(name, v); } } try { xpipeline.run(); } catch (XProcException e) { throw e; } catch (Exception e) { throw new XProcException(e); } Hashtable<String, ReadablePipe> pipeoutputs = new Hashtable<String, ReadablePipe> (); Set<String> pipeouts = xpipeline.getOutputs(); for (String port : pipeouts ) { ReadablePipe rpipe = xpipeline.readFrom(port); rpipe.canReadSequence(true); pipeoutputs.put(port, rpipe); } return pipeoutputs; } } // // //Copyright (C) 2008,2009,2010,2011,2012 David A. Lee. // //The contents of this file are subject to the "Simplified BSD License" (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.opensource.org/licenses/bsd-license.php // //Software distributed under the License is distributed on an "AS IS" basis, //WITHOUT WARRANTY OF ANY KIND, either express or implied. //See the License for the specific language governing rights and limitations under the License. // //The Original Code is: all this file. // //The Initial Developer of the Original Code is David A. Lee // //Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // //Contributor(s): none. //