Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Friday, 5 June 2009

Parametrized Xslt from javascript, using prototype

Here's the final product; the original page has 'a' links in a tag with id="displayableModules". The links have the form href="BadChannelsFile.xml#12345.0" where the module id is indicated after the file. This is a kind of xpointer syntax, but I remould it so the id gives the module part and then listen for 'click' events on those ids; this causes an XSLT to be run with the id as a parameter and a new window contains the SVG which results. Along the way, I experimented with various file loading mechanisms (so I made a separate loading class) but stuck with a synchronous Ajax request, although discovered that Safari requires the method to explicitly stated as 'get' in lower case. Enjoy...

var Loader = Class.create({

  initialize: function(){

    this.result="";

  },

  

  loadXml: function(docPath){

    this.ajaxLoad(docPath);

  },

  

  ajaxLoad: function(docPath){

  //bind the passed function to the original class

  //the method (get) needs to be explicitly written in lowercase for the Safari browser!

    new Ajax.Request(docPath, {asynchronous: false, onSuccess: this._callback.bind(this), method: "get",

    onFailure: function(r){alert("load failed");}})

  },

  

  _callback: function(r){

    this.result=r.responseXML;

  },

  

  doc: function(){

    if (this.result==""){

      alert("no doc");

    }

    return this.result;

  }

});


var Transformer = Class.create({

initialize: function(){

  this.processor = new XSLTProcessor();

  this.paramNames=[];

  this.paramValues=[];

  this.xslPath="";

  this.xmlPath="";

  this.fileLoader = new Loader();

},


setXslt: function(xslPath){

  this.xslPath = xslPath;

  this.fileLoader.loadXml(xslPath);

  this.stylesheet = this.fileLoader.doc();

},


setXml: function(docPath){

  this.xmlPath = docPath;

  this.fileLoader.loadXml(docPath);

  this.xmlDoc = this.fileLoader.doc();

},


setParam: function(paramName, paramValue){

  this.paramNames.push(paramName);

  this.paramValues.push(paramValue);

},


exec: function(thisdoc){

   this.processor.importStylesheet(this.stylesheet);

  for (var i=0;i<this.paramValues.length;i++){

    this.processor.setParameter("",this.paramNames[i], this.paramValues[i]);

  }

  var fragment = this.processor.transformToFragment(this.xmlDoc, thisdoc);

  return fragment;

}


});

//global functions

function changeLinks(){

  //take existing links in the div 'displayableModules' and add an id, and suppress the href link

  var allLinks=$("displayableModules").getElementsByTagName("a");

  for (var i=0;i

    var thisElement=$(allLinks[i]);

    var thisElementUrl=String(thisElement.href);

    var moduleId="module_".concat(thisElementUrl.substring(thisElementUrl.lastIndexOf('#') + 1));

    thisElement.setAttribute("id", moduleId);

    thisElement.setAttribute("name", thisElementUrl.substring(0,thisElementUrl.lastIndexOf('#')));

    thisElement.setAttribute("href","");

  }

  listenToLinks();

 }


function listenToLinks(){

//take existing links in the div 'displayableModules' and listen to them...

var allLinks=$("displayableModules").getElementsByTagName("a");

  for (var i=0;i

    var thisElement=$(allLinks[i]);

    var thisModule=String(thisElement.id);

    thisElement.observe('click',transform);

  }

}


function transform(e) {

  var moduleElement=e.element();

  var thisModule=moduleElement.id;

  var sourceFile=moduleElement.name;

  var transformer = new Transformer();

  transformer.setXslt("./xsl/graph.xsl");

  transformer.setXml(sourceFile);

  transformer.setParam("id",thisModule.substring(7));

  w=window.open("",thisModule,"width=670,height=500");

  w.document.open();

  w.document.write(''<span style="color: #000000"> + thisModule + </span>'

Bad channels for module ' + thisModule.substring(7) + '

');

  f=transformer.exec(w.document);

  w.document.getElementById('insert').appendChild(f);

  w.document.close();

}

document.observe('dom:loaded', changeLinks);



Wednesday, 3 June 2009

Prototype and running XSLT from JavaScript

I had some problem marrying the usual method of running an XSLT with prototype's library. Here's my project: Given an xml file of 'bad channel identifiers' for a module (where channels run 0-767), display the bad channels as bars on a graph in SVG in response to a user clicking on another web page link somewhere. I chose to generate the SVG using a parametrised XSLT, but I need to pass the parameters...so I'll be running the XSLT 'manually' from JavaScript instead of using the stylesheet association.
Step 1. : Perform a transform manually using a loaded stylesheet and xml. I'll load both via an Ajax request... (this is not production code, but might help someone... and note that I already loaded the prototype library)
var Transformer = Class.create({

initialize: function(){
  this.processor = new XSLTProcessor();
},

setXslt: function(xslPath){
  //need to bind, otherwise 'this' refers to the event context, not the class
  new Ajax.Request(xslPath, {asynchronous: false, onSuccess: this._setXsl.bind(this),
  onFailure: function(r){alert("failure to load xsl");}});
  
},
_setXsl: function(r){
  this.stylesheet=r.responseXML;
  if (this.stylesheet==''){
    alert("Empty stylesheet");
  }

  this.processor.importStylesheet(this.stylesheet);
},

setXml: function(docPath){
  //need to bind, otherwise 'this' refers to the event context, not the class
   new Ajax.Request(docPath, {asynchronous: false, onSuccess: this._setXml.bind(this),
  onFailure: function(r){alert("failure to load xml");}});
},

_setXml: function(r){
  this.xmlDoc = r.responseXML;
  if (this.xmlDoc==''){
    alert("Empty xml doc");
  }
 },

exec: function(){
  var fragment = this.processor.transformToFragment(this.xmlDoc, document);
  return fragment;
}

});

function transform() {
var transformer = new Transformer();
transformer.setXslt("xsl/test.xsl");
transformer.setXml("xml/hello.xml");
f = transformer.exec();
$('insert').appendChild(f);
}