Package client.net.sf.saxon.ce

Source Code of client.net.sf.saxon.ce.Xslt20ProcessorImpl

package client.net.sf.saxon.ce;

import client.net.sf.saxon.ce.Controller.APIcommand;
import client.net.sf.saxon.ce.LicenseException;
import client.net.sf.saxon.ce.client.HTTPHandler;
import client.net.sf.saxon.ce.client.HTTPHandler.State;
import client.net.sf.saxon.ce.dom.HTMLDocumentWrapper;
import client.net.sf.saxon.ce.dom.HTMLNodeWrapper;
import client.net.sf.saxon.ce.dom.XMLDOM;
import client.net.sf.saxon.ce.dom.HTMLDocumentWrapper.DocType;
import client.net.sf.saxon.ce.expr.Expression;
import client.net.sf.saxon.ce.expr.XPathContext;
import client.net.sf.saxon.ce.expr.XPathContextMajor;
import client.net.sf.saxon.ce.expr.instruct.GlobalVariable;
import client.net.sf.saxon.ce.js.IXSLFunction;
import client.net.sf.saxon.ce.lib.GenericLogHandler;
import client.net.sf.saxon.ce.lib.JavaScriptAPIException;
import client.net.sf.saxon.ce.lib.NamespaceConstant;
import client.net.sf.saxon.ce.lib.StandardErrorListener;
import client.net.sf.saxon.ce.lib.TraceListener;
import client.net.sf.saxon.ce.om.Axis;
import client.net.sf.saxon.ce.om.DocumentInfo;
import client.net.sf.saxon.ce.om.Item;
import client.net.sf.saxon.ce.om.NamePool;
import client.net.sf.saxon.ce.om.NodeInfo;
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.pattern.JSObjectPattern;
import client.net.sf.saxon.ce.pattern.NodeKindTest;
import client.net.sf.saxon.ce.pattern.NodeSetPattern;
import client.net.sf.saxon.ce.trace.XSLTTraceListener;
import client.net.sf.saxon.ce.trans.CompilerInfo;
import client.net.sf.saxon.ce.trans.Err;
import client.net.sf.saxon.ce.trans.Mode;
import client.net.sf.saxon.ce.trans.Rule;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.util.URI;
import client.net.sf.saxon.ce.type.ItemType;
import client.net.sf.saxon.ce.value.SequenceType;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestTimeoutException;
import com.google.gwt.http.client.Response;
import com.google.gwt.logging.client.LogConfiguration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Window;
//import com.google.gwt.xml.client.XMLParser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.timepedia.exporter.client.ExporterUtil;


/**
* This class represents the XSLT 2.0 processor, which is the top-level object implemented by Saxon-CE
* Logging is implemented using GWT Logging - documentation at:
* http://code.google.com/webtoolkit/doc/latest/DevGuideLogging.html
*/
public class Xslt20ProcessorImpl implements EntryPoint {

    final Configuration config = new Configuration();
    private boolean registeredForEvents = false;
    private boolean principleEventListener = false;
    PreparedStylesheet stylesheet = null;
    private JavaScriptObject successCallback = null;
    Controller localController = new Controller(config, true);      
    private static Logger logger = Logger.getLogger("XSLT20Processor");
  
    public void onModuleLoad() {
      if (LogConfiguration.loggingIsEnabled()){
            SaxonceApi.setAnyExternalErrorHandler();
        LogController.initLogger();
        LogController.addJavaScriptLogHandler();
      }
     
      logger.log(Level.FINE, "GWT Module Load initated by page: " + Document.get().getTitle());
      if (LogConfiguration.loggingIsEnabled()) {
        String href = Window.Location.getHref();
        if (href != null && href.startsWith("file:")) {
          logger.warning("The file:// protocol in use may cause 'permission denied' errors in Saxon-CE - unless the browser's 'strict-origin-policy' has been relaxed.");
        }
      }
        //register();
        ExporterUtil.exportAll();
        SaxonceApi.register();

        // License code commented out - change 1.1 from decision: saxon-ce opensource    
/*        try {
          Verifier.loadLicense();
          if (LogConfiguration.loggingIsEnabled()){
            Verifier.displayLicenseMessage();
          }
           
        } catch (LicenseException le) {
          handleException(le, "onModuleLoad");
          return;
        } */
       
        // perform JavaScript callback or use <script> element to initate transform
        JavaScriptObject saxonceLoadCallback = getCallback();
        if (saxonceLoadCallback != null) {
          logger.log(Level.FINE, "Executing 'onSaxonceLoad' callback...");
          try {
          executeCallback(saxonceLoadCallback);
          } catch(JavaScriptException jse) {
            handleException(jse, "onModuleLoad");
          } catch(Exception je) {
            handleException(je, "onModuleLoad");
          }
        }
      // do transform based on <script> element - this might be needed as
        // as a callback - for test-harness for example
      doTransformation();
    }
   
    private native JavaScriptObject getCallback() /*-{
       if ($wnd.onSaxonLoad && typeof $wnd.onSaxonLoad == 'function') {
           return $wnd.onSaxonLoad;
       } else {
           return null;
       }
     }-*/;
   
    // sets the window object as the owner object
    private native void executeCallback(JavaScriptObject callback) /*-{
         callback.apply($wnd);
    }-*/;
         
    // script nodes found when module loaded
    private static NodeList<Element> scriptsOnLoad;
   
    /**
     * Gets script element list the first time this is called
     * Used by Verifier and Xslt20Processor.doTransformation()
     */
    public static NodeList<Element> getScriptsOnLoad() {
      if (scriptsOnLoad == null) {
        scriptsOnLoad = Document.get().getElementsByTagName("s" +
            "cript");
      }
      return scriptsOnLoad;
    }
   
    public JavaScriptObject getSuccess() {
      return successCallback;
    }
   
    public XSLT20Processor successOwner = null;
   
    public void setSuccess(JavaScriptObject sFunction, XSLT20Processor sOwner) {
      successCallback = sFunction;
      successOwner = sOwner;
    }
   
  
   
    /**
     * The entry point for transforms initiate on module load,
     * fetches settings from the <code>application/xslt+xml style</code> element
     */
    public void doTransformation() {
      Logger logger = Logger.getLogger("Xstl20Processor");
        try {        
            NodeList<Element> scripts = getScriptsOnLoad();
            String sourceURI = null;
            String styleURI = null;
            String initialMode = null;
            String initialTemplate = null;
            boolean styleElementExists = false;
            for (int i=0; i<scripts.getLength(); i++) {
                String type = scripts.getItem(i).getAttribute("type");
                if (type.equals("application/xslt+xml")) {
                  styleElementExists = true;
                    styleURI = scripts.getItem(i).getAttribute("src");
                    sourceURI = scripts.getItem(i).getAttribute("data-source");
                    initialMode = scripts.getItem(i).getAttribute("data-initial-mode");
                    initialTemplate = scripts.getItem(i).getAttribute("data-initial-template");
                    break;
                }
            }
           
            if (!styleElementExists) {
              logger.info("Saxon-CE API initialised");
              return;
            } else if (styleURI == null)
              { throw new XPathException("No XSLT stylesheet reference found"); }

            JavaScriptObject sourceDoc = null;
            String absSourceURI = null;
            if (sourceURI != null && sourceURI.length() != 0) {
              String pageHref = Window.Location.getHref();
                absSourceURI = (new URI(pageHref).resolve(sourceURI)).toString();
                if (pageHref.equals(absSourceURI)) {
                  throw new XPathException("Cannot load XML with same URI as the host page");
                }

                sourceDoc = SaxonceApi.createAsyncDoc(absSourceURI); // config.buildDocument(absSourceURI);

            } else if (initialTemplate == null) {
              throw new XPathException("No data-source attribute or data-initial-template value found - one is required");
            }

            String absStyleURI = (new URI(Window.Location.getHref()).resolve(styleURI)).toString();
            DocumentInfo styleDoc;
            try {
                styleDoc = config.buildDocument(absStyleURI);
            } catch (XPathException e) {
              String reportURI = (absSourceURI != null)? absSourceURI : styleURI;
              throw new XPathException("Failed to load XSLT stylesheet " + reportURI + ": " + e.getMessage());
            }
            config.getDocumentPool().add(styleDoc, absStyleURI);     // where document('') can find it
            Element body = getBodyElement();
           
            localController.setInitialMode(initialMode);
            localController.setInitialTemplate(initialTemplate);
            localController.setApiCommand(APIcommand.UPDATE_HTML);
            localController.setTargetNode(Document.get());          // target node is the document node
           
            renderXML(sourceDoc, styleDoc, body);                   // principle output is to the body element

        } catch (Exception err) {
          logger.log(Level.SEVERE, err.getMessage());
        }
    }
   
    public static Element getBodyElement() {
      Element body = Document.get().getElementsByTagName("BODY").getItem(0);
      if (body == null) {
        body = Document.get().getElementsByTagName("body").getItem(0);
      }
      return body;
    }
      
    public void continueWithSourceDocument(
            final DocumentInfo sourceDoc,
            final String styleURI,
            final String initialMode,
            final String initialTemplate) {
//        RequestBuilder request = new RequestBuilder(RequestBuilder.GET, styleURI);
//        request.setHeader("Cache-Control", "no-cache");
//        request.setCallback(new RequestCallback() {
//            public void onResponseReceived(Request request, Response response) {
//                com.google.gwt.xml.client.Document styleXML = XMLParser.parse(response.getText());
//                DocumentInfo styleDoc = new XMLDocumentWrapper(styleXML, styleURI, config);
//                renderXML(sourceDoc, styleDoc, initialMode, initialTemplate, Document.get().getElementById("target"));
//            }
//            public void onError(Request request, Throwable exception) {
//                Window.alert(exception.getMessage());
//            }
//        });
    }
   
    /**
     * Implementation of XSLT20Processor API - only handles xml dom - must
     * use transformToFragment or updateHTMLDocument for html dom
     * @param sourceDoc
     */
    public void updateHTMLDocument(JavaScriptObject sourceDoc, Document targetDoc, APIcommand cmd) {
    if (targetDoc == null) {
      targetDoc = Document.get();
    }
    localController.setApiCommand(cmd);
    localController.setTargetNode(targetDoc);
      renderXML(sourceDoc, importedStylesheet, getBodyElement());
    }
   
    public Node transformToDocument(JavaScriptObject sourceDoc) {
    localController.setTargetNode(XMLDOM.createDocument(localController.getBaseOutputURI()));
    localController.setApiCommand(APIcommand.TRANSFORM_TO_DOCUMENT);
      Document targetDoc = XMLDOM.createDocument(localController.getBaseOutputURI());
      return renderXML(sourceDoc, importedStylesheet, targetDoc);
    }
   
    public Node transformToFragment(JavaScriptObject sourceDoc, Document ownerDocument) {
      Document owner = (ownerDocument == null)? XMLDOM.createDocument(localController.getBaseOutputURI()) : ownerDocument;
    Node targetDocumentFragment = HTMLDocumentWrapper.createDocumentFragment(owner);
    // Set the owner document for result document output fragments:
    localController.setTargetNode(owner);
    localController.setApiCommand(APIcommand.TRANSFORM_TO_FRAGMENT);
      return renderXML(sourceDoc, importedStylesheet, targetDocumentFragment);
    }
   
    private DocumentInfo importedStylesheet;
   
    /**
     * Imports new stylesheet and de-registers sinks for specific events from
     * any previous stylesheet for this processor
     * @param doc
     */
    public void importStylesheet(JavaScriptObject doc) {
      deregisterEventHandlers();
      try {
      importedStylesheet = SaxonceApi.getDocSynchronously(doc, config);
      } catch(XPathException e) {
        handleException(e, "importStylesheet");
      }
    }
   
    // fetched either synchronously or asynchronously
    NodeInfo fetchedSourceDoc;
    boolean transformInvoked;
    boolean docFetchRequired;
  
    public Node renderXML(JavaScriptObject inSourceDoc,
                          DocumentInfo styleDoc,
                          com.google.gwt.dom.client.Node target) {
        try {
          if (styleDoc == null) {
            throw new Exception("Stylesheet for transform is null");
          }
          docFetchRequired = inSourceDoc != null;
            CompilerInfo info = config.getDefaultXsltCompilerInfo();
            info.setErrorListener(new StandardErrorListener());

            String asyncSourceURI = null;

            // for now - don't use aync when using the JavaScript API calls that return a result
            if (docFetchRequired &&
                (localController.getApiCommand() == APIcommand.UPDATE_HTML || (successCallback != null))) {
              asyncSourceURI = SaxonceApi.getAsyncUri(inSourceDoc);
              if (asyncSourceURI != null && asyncSourceURI.toLowerCase().startsWith("file:")) {
                asyncSourceURI = null; // force synchronous fetch if using file-system protocol
              }
            }

           
            // ----------- Start async code -------------
            fetchedSourceDoc = null;
            transformInvoked = false;
           
            if (asyncSourceURI != null) {
              final String URI = asyncSourceURI;
              final Node transformTarget = target;

              logger.log(Level.FINE, "Aynchronous GET for: " + asyncSourceURI);
              final HTTPHandler hr = new HTTPHandler();

             hr.doGet(asyncSourceURI, new RequestCallback() {
              
               public void onError(Request request, Throwable exception) {
                 //hr.setErrorMessage(exception.getMessage());
                 String msg = "HTTP Error " + exception.getMessage() + " for URI " + URI;
                 handleException (new RuntimeException(msg), "onError");
               }
 
               public void onResponseReceived(Request request, Response response) {
                 int statusCode = response.getStatusCode();
                   if (statusCode == 200) {
                     Logger.getLogger("ResponseReceived").fine("GET Ok for: " + URI);
                     Node responseNode;
                     try {
                     responseNode = (Node)XMLDOM.parseXML(response.getText());
                     } catch(Exception e) {
                      handleException (new RuntimeException(e.getMessage()), "onResponseReceived");
                      return;
                     }
                     DocumentInfo responseDoc = config.wrapXMLDocument(responseNode, URI);
                     // now document is here, we can transform it
                     Node result = invokeTransform(responseDoc, transformTarget);
                     hr.setResultNode(result); // TODO: This isn't used yet
                       // handle OK response from the server
                   } else if (statusCode < 400) {
                     // transient
                   } else {
                     String msg = "HTTP Error " + statusCode + " " + response.getStatusText() + " for URI " + URI;
                     handleException (new RuntimeException(msg), "onResponseReceived");
                     //hr.setErrorMessage(statusCode + " " + response.getStatusText());
                   }
               } // ends inner method
             }// ends inner class
             ); // ends doGet method call
            }
            // -------------- End async code
                      
            /// we can compile - even while sourcedoc is being fetched asynchronously
           
            if (stylesheet == null) {
              if (LogConfiguration.loggingIsEnabled()) {
                LogController.InitializeTraceListener();
              }
              logger.log(Level.FINE, "Compiling Stylesheet...");
              PreparedStylesheet sheet = new PreparedStylesheet(config, info);
              sheet.prepare(styleDoc);
              stylesheet = sheet;
              logger.log(Level.FINE, "Stylesheet compiled OK");
            }
           
            // for async operation - this is called within the callback - so don't call here           
            if (asyncSourceURI == null && inSourceDoc != null) {
              int nodeType = (Node.is(inSourceDoc))? ((Node)inSourceDoc).getNodeType() : 0;

              if (nodeType > 0 && nodeType != Node.DOCUMENT_NODE) {
                // add a document node wrapper
                Node sourceNode = (Node)inSourceDoc;
                Document sourceDoc = sourceNode.getOwnerDocument();
                  HTMLDocumentWrapper htmlDoc = new HTMLDocumentWrapper(sourceDoc, sourceDoc.getURL(), config, DocType.UNKNOWN);
                  fetchedSourceDoc = htmlDoc.wrap(sourceNode);
              } else {
                fetchedSourceDoc = SaxonceApi.getDocSynchronously(inSourceDoc, config);
              }
            }
            // this method only runs if transformInvoked == false - need to get sourceDoc reference if not invoked

            return invokeTransform(fetchedSourceDoc, target);

            //method ends - allowing onResponceReceived handler to call invokeTransform for async operation
        } catch (Exception e) {
          handleException(e, "renderXML");      
            return null;
        }
    }
   
    public static native boolean isNonDocNode(JavaScriptObject obj) /*-{
    return (typeof obj.getNodeType == "function" && obj.getNodeType() != 9);
  }-*/;
         
    private List<Mode> registeredEventModes = null;
    private boolean registeredProcessorForNonDomEvents = false;
   
    private void registerNonDOMevents(Controller controller) throws XPathException {
        for (Mode eventMode : registeredEventModes) {
          ArrayList<Rule> nonDomRules = eventMode.getVirtualRuleSet();
          if (nonDomRules != null) {
            if (!registeredProcessorForNonDomEvents){
              registeredProcessorForNonDomEvents = true;
              Controller.addNonDomEventProcessor(this);
            }
            String eventName = eventMode.getModeName().getLocalName();
            for (Rule r : nonDomRules) {
              JavaScriptObject eventTarget = null;
              eventTarget = ((JSObjectPattern)r.getPattern()).evaluate(controller.newXPathContext());
              bindTemplateToWindowEvent(eventName, eventTarget);
            }
          }
         
        }

    }
      
    public static native String bindTemplateToWindowEvent(String eventName, JavaScriptObject target) /*-{
    target[eventName] = $entry(function(eventArg) {@client.net.sf.saxon.ce.Xslt20ProcessorImpl::relayNonDomEvent(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(eventName, target, eventArg)});
  }-*/;
   
    public static void relayNonDomEvent(String name, JavaScriptObject obj, JavaScriptObject eventArg){
      JavaScriptObject event = (eventArg == null)? getWindowEvent(): eventArg;
      Controller.relayNonDomEvent(name, obj, event);
    }
   
    public static native JavaScriptObject getWindowEvent() /*-{
    return $wnd.event;
  }-*/;
   
    private void registerEventHandlers(Controller controller) throws XPathException {
      // add an event listener to capture registered event modes
      if (registeredEventModes != null) {
        return;
      }
        Element docElement = (com.google.gwt.user.client.Element)(Object)Document.get();
        registeredEventModes = controller.getRuleManager().getModesInNamespace(NamespaceConstant.IXSL);
        // Restriction: only one event listener per element
        if (registeredEventModes.size() > 0 && !registeredForEvents) {
          registeredForEvents = true;
          registerNonDOMevents(controller);
          if (DOM.getEventListener((com.google.gwt.user.client.Element)docElement) == null) {
            principleEventListener = true;
              DOM.setEventListener((com.google.gwt.user.client.Element) docElement, new EventListener() {
                  public void onBrowserEvent(Event event) {
 
                      EventTarget eTarget = event.getEventTarget();
                      Node eventNode;
                      if (Node.is(eTarget)) {
                        eventNode = Node.as(eTarget);                  
                      } else {
                        eventNode = Node.as(getCorrespondingSVGElement(eTarget));
                          if (eventNode == null) {
                            return;
                          }
                      }
                      bubbleApplyTemplates(eventNode, event);
                  }
              });
          } else {
            // can't register for event so register for relayEvent
            Controller.addEventProcessor(this);
          }
        }
        // Events for all processor instances may register 1 or more event types
        for (Mode eventMode : registeredEventModes) {
          String eventName = eventMode.getModeName().getLocalName();
          if (!eventName.startsWith("on")) {
            logger.warning("Event name: '" + eventName + "' is invalid - names should begin with 'on'");
          } else {
            eventName = eventName.substring(2);
          }
            int eventNo = Event.getTypeInt(eventName);
            DOM.sinkEvents((com.google.gwt.user.client.Element)docElement,
                eventNo | DOM.getEventsSunk((com.google.gwt.user.client.Element) docElement));

        }

    }
   
    public void deregisterEventHandlers() {
      // Don't deregister because this will affect any other instances of the processor
//      Element docElement = (com.google.gwt.user.client.Element)(Object)Document.get();     
//      DOM.sinkEvents((com.google.gwt.user.client.Element)docElement, 0);
//      registeredEventModes = null;
    }
   
    /**
     * Returns the SVG DOM element associated with an external element that's an SVGElementInstance object
     * E.g. If a <code>use</code> element references a <code>rect</code> element - using xlink:href - then,
     * if the <code>rect</code> object is passed as a parameter, the <code>use</code> element is returned.
     */
    public native JavaScriptObject getCorrespondingSVGElement(JavaScriptObject obj) /*-{
      if (obj.correspondingElement) {
        return obj.correspondingElement;
      }
      return null;
    }-*/;
   
  
    /**
     * This invokes a transform, but it may be called either on an async callback or directly
     * We need to ensure this method runs once and only once for a single transform request -
     * It's possible for either the main code branch which performs the compile or the async callback
     * which depends on the compile to makes the call first.
     */
    private Node invokeTransform(NodeInfo inDoc, com.google.gwt.dom.client.Node target) {
        // in case stylesheet not ready but doc has been fetched:
      if (fetchedSourceDoc == null) {
        fetchedSourceDoc = inDoc;
      }
      // check to ensure conditions required for a transform have been met
      if (transformInvoked || stylesheet == null ||
          (docFetchRequired && fetchedSourceDoc == null)) {
        return null;
      }
      transformInvoked = true;
     
      try {
            final Controller controller = stylesheet.newTransformer();
            localController.setSourceNode(fetchedSourceDoc);
            controller.importControllerSettings(localController);
            logger.log(Level.FINE, "Commencing transform type:" + controller.getApiCommand().toString());
            Node outResult = controller.transform(fetchedSourceDoc, target);
            logger.log(Level.FINE, "Transform complete");
            localController.importResults(controller);
            registerEventHandlers(controller);
            if (successCallback != null) {
              successOwner.invokeSuccess(successCallback);
            }
            return outResult;
      } catch(Exception e) {
        handleException(e, "invokeTransform");
        return null;
      }
    }
   
         
    public static void handleException(Exception err, String prefix) {
      if (err instanceof JavaScriptAPIException){
        // don't log and re-throw exceptions thrown only for the benefit of the API
        return;
      }
      String excName;
      prefix = (prefix == null || prefix.length() == 0)? "" : " in " + prefix + ":";
      boolean logException = true;
     
      if (err instanceof XPathException) {
        excName = "XPathException";
        XPathException xe = (XPathException)err;
        logException = !xe.hasBeenReported();
      } else if (err instanceof LicenseException) {
        excName = "LicenseException";
      } else {
        excName = "Exception " + err.getClass().getName();
      }
      String message = excName + prefix + " " + err.getMessage();
      if (logException) {
        logger.log(Level.SEVERE, message);
      }
      err.printStackTrace();
      if (SaxonceApi.doThrowJsExceptions())
      {
        throw new JavaScriptAPIException("[js] " + message);
      }
    }
   
    // emulate bubbling up events by iterating through ancestors that have matching rule, starting with the
    // targetNode
   
    private Mode getModeFromEvent(Event event) {
      Mode result = null;
      String mode = "on" + event.getType(); // eg. onclick
      for (Mode m: registeredEventModes){
        if (m.getModeName().getLocalName().equals(mode)) {
          result = m;
          break;
        }
      }
      return result;
    }
    public void bubbleApplyTemplates(Node node, Event event)  {
      if (principleEventListener) {
        Controller.relayEvent(node, event); // make a call to this method for other instances
      }
      NodeInfo eventNode = ((HTMLDocumentWrapper)config.getHostPage()).wrap(node);
      SequenceIterator bubbleElements = eventNode.iterateAxis(Axis.ANCESTOR, NodeKindTest.ELEMENT);
      Controller controller = stylesheet.newTransformer();
      try {
          controller.importControllerSettings(localController);
        XPathContext ruleContext = controller.newXPathContext();
        Mode matchedMode = getModeFromEvent(event);
       
        if (matchedMode == null) {
          return;
        }
       
        // walk up the tree until we find an element with matching rule for the event mode

        NodeInfo element = eventNode;
          while (element != null) {
              Rule matchedRule = matchedMode.getRule(element, ruleContext);
              if (matchedRule != null && eventPropertyMatch(event, matchedRule)) {
                logger.log(Level.FINER, "Bubble Apply-Templates - Mode: " + matchedMode.getModeName().getLocalName() +
                    " Element: " + controller.getNamePool().getLocalName(element.getNameCode()));
                applyEventTemplates(matchedMode.getModeName().getClarkName(), element, event, null);
                if (matchedRule.getIxslPreventDefault()) {
                  event.preventDefault();
                }
                break;
              }
              element = (NodeInfo)bubbleElements.next();
          }
      } catch (Exception e) {
        handleException(e, "bubbleApplyTemplates");
      }
    }
   
    private static boolean eventPropertyMatch(Event event, Rule matchedRule){
      String eventProperty = matchedRule.getEventProperty();
      if (eventProperty == null){
        return true;
      }
      String[] all = eventProperty.split("\\s");
      String eventPropertyValue = getEventProperty(event, all[0]);
      if (all.length < 2 || eventPropertyValue == null){      
        return true;
      }
      boolean matches = false;

      for (int i = 1; i < all.length; i++){
        if (eventPropertyValue.equals(all[i]) ){
          matches = true;
          break;
        }
      }
      return matches;
    }
     
    private static native String getEventProperty(Event evt, String propName) /*-{
    var prop = evt[propName];
    if (prop != null) {
      return String(prop);
    }
    return null;
    }-*/;
      
    // called by bubbleApplyTemplates which is the registered event handler
    // at the document node level for all specified ixsl modes     
    public void applyEventTemplates(String mode, NodeInfo start, JavaScriptObject event, JavaScriptObject object) {
        try {
          // for case where this is a non-user event - to prevent error
          if (start == null) {
            start = config.getHostPage();
          }
          logger.log(Level.FINER, "OnEvent Apply-Templates - Mode: " + mode + " Event: " + event.toString());
            Controller controller = stylesheet.newTransformer();

            controller.importControllerSettings(localController);
            // override any imported initial mode with that for the event
            controller.setInitialTemplate(null);
            controller.setInitialMode(mode);
            controller.setUserData("Saxon-CE", "current-event", event);
            controller.setUserData("Saxon-CE", "current-object", object);

            controller.transform(start, controller.getTargetNode());
        } catch (Exception err) {
          handleException(err, "mode: '" + mode +"' event: '" + event.toString());
        }
    }
   
    public Controller getController() {
      return localController;
    }
}

// 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 http://mozilla.org/MPL/2.0/.
// This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.


TOP

Related Classes of client.net.sf.saxon.ce.Xslt20ProcessorImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.