package client.net.sf.saxon.ce; import java.lang.annotation.ElementType; import org.timepedia.exporter.client.Export; import org.timepedia.exporter.client.ExportJsInitMethod; import org.timepedia.exporter.client.ExportPackage; import org.timepedia.exporter.client.Exportable; import client.net.sf.saxon.ce.Controller.APIcommand; import client.net.sf.saxon.ce.dom.XMLDOM; import client.net.sf.saxon.ce.js.IXSLFunction; import client.net.sf.saxon.ce.om.SequenceIterator; import client.net.sf.saxon.ce.om.StructuredQName; import client.net.sf.saxon.ce.om.ValueRepresentation; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.tree.iter.JsArrayIterator; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Node; @Export(value="XSLT20Processor") @ExportPackage("Saxonce") /** * JavaScript API for the XSLTProcessor - mirrors the standard * XSLTProcessor specification for JavaScript - gwt-exporter is * used to convert this class to JavaScript API * - uses details from the mozilla documentation at: * https://developer.mozilla.org/en/Using_the_Mozilla_JavaScript_interface_to_XSL_Transformations * * This class provides a capability to perform a Saxon-CE transform on an XML/HTML DOM document * For HTML, the passed the exisitng DOM document is modified - for XML, a new XML DOM object is * created */ public class XSLT20Processor implements Exportable { Xslt20ProcessorImpl processor; Controller controller; public XSLT20Processor(JavaScriptObject stylesheet) { this(); // call constructor if (stylesheet != null) { processor.importStylesheet(stylesheet); } } private JavaScriptObject jsThis = null; /** * Keep instance of the JavaScript wrapped version - to * be used when making a callback */ public void setThis(JavaScriptObject jsObj) { jsThis = jsObj; } public XSLT20Processor() { processor = new Xslt20ProcessorImpl(); // get an 'inert' controller instance - used only for getting/setting controller properties controller = processor.getController(); SaxonceApi.setProcessorWasJsInitiated(); } /** * Erases any parameter values set using setParameter method */ public void clearParameters() { controller.clearParameters(); } /** * Returns the value of the parameter as a String. * @param namespaceURI the parameter namespace * @param localName the local name of the parameter * @return the string value of the parameter */ public Object getParameter(String namespaceURI, String localName) { String ns = (namespaceURI == null)? "" : namespaceURI; try { StructuredQName qn = new StructuredQName("", ns, localName); ValueRepresentation vr = controller.getParameter(qn); return IXSLFunction.convertToJavaScript(vr); } catch(Exception e) { Xslt20ProcessorImpl.handleException(e, "getParameter"); } return null; } /** * * @param stylesheet This may be either a document node or an xsl:transform or * xsl:stylesheet element. If a document node then the transform can be a literal * element transform or a full transform */ // what happens if the imported node is modified, do we use a // cached stylesheet? public void importStylesheet(JavaScriptObject stylesheet) { processor.importStylesheet(stylesheet); } public void setSuccess(JavaScriptObject success) { processor.setSuccess(success, this); } public JavaScriptObject getSuccess() { return processor.getSuccess(); } public void invokeSuccess(JavaScriptObject callback) { executeSuccessCallback(callback, jsThis); } // sets the window object as the owner object public native void executeSuccessCallback(JavaScriptObject callback, JavaScriptObject proc) /*-{ callback.call($wnd, proc); }-*/; /** * Deletes a parameter value set using the setParameter method * @param namespaceURI the parameter namespace * @param localName the local name of the parameter */ public void removeParameter(String namespaceURI, String localName) { String ns = (namespaceURI == null)? "" : namespaceURI; try { StructuredQName qn = new StructuredQName("", ns, localName); controller.removeParameter(qn); } catch(Exception e) { Xslt20ProcessorImpl.handleException(e, "getParameter"); } } /** * Restore the XSLTProcessor20 instance to its default state */ public void reset() { controller.reset(); processor.deregisterEventHandlers(); } /** * Set the value of a parameter - the value must be convertible to an xdmValue type * @param namespaceURI the namespace of the parameter * @param localName the local name of the parameter * @param value the value, as a boolean/string/number or DOM node sequence to assign to the parameter * @return */ // extension required to set any sequence of items (xdmValue) as a parameter as per XSLT2.0 spec // but emphasis initially on string, boolean and integer public void setParameter(String namespaceURI, String localName, Object value) { String ns = (namespaceURI == null)? "" : namespaceURI; try { StructuredQName qn = new StructuredQName("", ns, localName); controller.setParameter(qn, getValue(value)); } catch (Exception e) { Xslt20ProcessorImpl.handleException(e, "setParameter"); } } private ValueRepresentation getValue(Object jso) throws XPathException { SequenceIterator iterator = IXSLFunction.convertFromJavaScript(jso, processor.config); if (iterator instanceof JsArrayIterator) { return (ValueRepresentation)iterator; } else { return iterator.next(); } } /** * updates the HTML document object passed as the target - note that any event handling * target the host HTML page's DOM, which may not be the target document * * @param sourceObject the XML source document - may only be null if an initialTemplate * name has been set * @param targetDocument the target HTML or XHTML document object -straight XML is not * supported because updates are either via result-document HTML references or, * for the principle output, direct to the HTML body element */ // for XSLT 2.0 sourceNode may be null public void updateHTMLDocument(JavaScriptObject sourceObject, Document targetDocument) { processor.updateHTMLDocument(sourceObject, targetDocument, APIcommand.UPDATE_HTML); } public void transformToHTMLFragment(JavaScriptObject sourceObject, Document targetDocument) { processor.updateHTMLDocument(sourceObject, targetDocument, APIcommand.TRANSFORM_TO_HTML_FRAGMENT); } /** * * @param sourceNode The source node to transform - may be null provided that initial * template was set using setTemplate() - this is not standard XsltProcessor behaviour * because XSLT 1.0 does not support the setting of the initial template * @return The return type is either XMLDocument, HTMLDocument or XMLDocument with a * single root element containing a text node depending on whether xsl:output is set * to be XML, HTML or Text respectively */ // for XSLT 2.0 sourceNode may be null public Document transformToDocument(JavaScriptObject sourceNode) { return (Document)processor.transformToDocument(sourceNode); } /** * Returns a DocumentFragment object. Will only produce HTML DOM objects if the owner document passed * as an argument is an HTMLDocument. Any result documents output from this method will also be * DocumentFragment objects * @sourceNode A Document object or a Saxonce 'placeholder' object - used for async operations, or * null if initialTemplate is set * @ownerDocument Sets The owner document for all DocumentFragments returned * @return return a DOM DocumentFragment node with the owner document the same as that supplied * as a parameter */ // for XSLT 2.0 sourceNode may be null public Node transformToFragment(JavaScriptObject sourceNode, Document ownerDocument) { return processor.transformToFragment(sourceNode, ownerDocument); } /* * Extensions for XSLT 2.0 */ public String getInitialMode() { return controller.getInitialMode(); } public String getInitialTemplate() { return controller.getInitialTemplate(); } public void setInitialMode(String mode) { try { controller.setInitialMode(mode); } catch (Exception e) { Xslt20ProcessorImpl.handleException(e, "setInitialMode"); } } public void setInitialTemplate(String template) { try { controller.setInitialTemplate(template); } catch (Exception e) { Xslt20ProcessorImpl.handleException(e, "setInitialTemplate"); } } public void setBaseOutputURI(String URI) { controller.setBaseOutputURI(URI); } /** * Return result-documents as a JS map of URI/dom name/value pairs * Note that the base-output-uri setting is use to resolve relative uris * @return */ public JavaScriptObject getResultDocuments() { return controller.getResultDocURIArray(); } public JavaScriptObject getResultDocument(String URI) { return controller.getResultDocument(URI); } public void setCollation() { // TODO: this could also be tried out using Saxon feature keys } }