/**
* xslTransform
* Tools for XSLT transformations; jQuery wrapper for Sarissa .
* See jQuery.fn.log below for documentation on $.log().
* See jQuery.fn.getTransform below for documention on the $.getTransform().
* See var DEBUG below for turning debugging/logging on and off.
*
* @version 20071203
* @since 2006-07-05
* @copyright Copyright (c) 2006 Glyphix Studio, Inc. http://www.glyphix.com
* @author Brad Brizendine , Matt Antone
* @license MIT http://www.opensource.org/licenses/mit-license.php
* @requires >= jQuery 1.0.3 http://jquery.com/
* @requires jquery.debug.js http://jquery.glyphix.com/
* @requires >= sarissa.js 0.9.7.6 http://sarissa.sourceforge.net/
*
* @example
* var r = xslTransform.transform('path-to-xsl.xsl','path-to-xml.xml');
* @desc Perform a transformation and place the results in var r
*
* @example
* var r = xslTransform.transform('path-to-xsl.xsl','path-to-xml.xml');
* var str = xslTransform.serialize( r );
* @desc Perform a transformation, then turn the result into a string
*
* @example
* var doc = xslTransform.load('path-to-xml.xml');
* @desc Load an xml file and return a parsed xml object
*
* @example
* var xml = 'bar';
* var doc = xslTransform.load(xml);
* @desc Load an xml string and return a parsed xml object
*/
var xslTransform = {
version: 20071203,
debug: false,
// init ... test for requirements
init: function(){
// check for v1.0.4 / v1.1 or later of jQuery
try{
parseFloat(jQuery.fn.jquery) >= 1;
}catch(e){
alert('xslTransform requires jQuery 1.0.4 or greater ... please load it prior to xslTransform');
}
// check for Sarissa
try{
Sarissa;
}catch(e){
alert('Missing Sarissa ... please load it prior to xslTransform');
}
// if no log function, create a blank one
if( !jQuery.log ){
jQuery.log = function(){};
jQuery.fn.debug = function(){};
}
// log the version
if(this.debug) jQuery.log( 'xslTransform:init(): version ' + xslTransform.version );
},
// initialize Sarissa's serializer
XMLSerializer: new XMLSerializer(),
/*
* serialize
* Turns the provided object into a string and returns it.
*
* @param data Mixed
* @returns String
*/
serialize: function( data ){
if(this.debug) jQuery.log( 'serialize(): received ' + typeof(data) );
// if it's already a string, no further processing required
if( typeof(data) == 'string' ){
return data;
}
return this.XMLSerializer.serializeToString( data );
},
/*
* load
* Attempts to load xml data by automatically sensing the type of the provided data.
*
* @param xml Mixed the xml data
* @returns Object
*/
load: function( xml ){
if(this.debug) jQuery.log( 'load(): received ' + typeof(xml) );
// the result
var r;
// if it's an object, assume it's already an XML object, so just return it
if( typeof(xml) == 'object' ){
return xml;
}
// if it's a string, determine if it's xml data or a path
// assume that the first character is an opening caret if it's XML data
if( xml.substring(0,1) == '<' ){
r = this.loadString( xml );
}else{
r = this.loadFile( xml );
}
if( r ){
// the following two lines are needed to get IE (msxml3) to run xpath ... set it on all xml data
r.setProperty( 'SelectionNamespaces', 'xmlns:xsl="http://www.w3.org/1999/XSL/Transform"' );
r.setProperty( 'SelectionLanguage', 'XPath' );
return r;
}else{
if(this.debug) $.log( 'Unable to load ' + xml );
return false;
}
},
/*
* loadString
* Parses an XML string and returns the result.
*
* @param str String the xml string to turn into a parsed XML object
* @returns Object
*/
loadString: function( str ){
if(this.debug) jQuery.log( 'loadString(): ' + str + '::' + typeof(str) );
// use Sarissa to generate an XML doc
var p = new DOMParser();
var xml = p.parseFromString( str, 'text/xml' );
if( !xml ){
if(this.debug) jQuery.log( 'loadString(): parseFromString() failed' );
return false;
}
return xml;
},
/*
* loadFile
* Attempts to retrieve the requested path, specified by url.
* If url is an object, it's assumed it's already loaded, and just returns it.
*
* @param url Mixed
* @returns Object
*/
loadFile: function( url ){
if(this.debug) jQuery.log( 'loadFile(): ' + url + '::' + typeof(url) );
if( !url ){
if(this.debug) jQuery.log( 'ERROR: loadFile() missing url' );
return false;
}
// variable to hold ajax results
var doc;
// function to receive data on successful download ... semicolon after brace is necessary for packing
this.xhrsuccess = function(data,str){
if(this.debug) jQuery.log( 'loadFile() completed successfully (' + str + ')' );
doc = data;
return true;
};
// function to handle downloading error ... semicolon after brace is necessary for packing
this.xhrerror = function(xhr,err){
// set debugging to true in order to force the display of this error
window.DEBUG = true;
if(this.debug) jQuery.log( 'loadFile() failed to load the requested file: (' + err + ') - xml: ' + xhr.responseXML + ' - text: ' + xhr.responseText );
doc = null;
return false;
};
// make asynchronous ajax call and call functions defined above on success/error
$.ajax({
type: 'GET',
url: url,
async: false,
success: this.xhrsuccess,
error: this.xhrerror
});
// check for total failure
if( !doc ){
if(this.debug) jQuery.log( 'ERROR: document ' + url + ' not found (404), or unable to load' );
return false;
}
// check for success but no data
if( doc.length == 0 ){
if(this.debug) jQuery.log( 'ERROR: document ' + url + ' loaded in loadFile() has no data' );
return false;
}
return doc;
},
/*
* transform
* Central transformation function: takes an xml doc and an xsl doc.
*
* @param xsl Mixed the xsl transformation document
* @param xml Mixed the xml document to be transformed
* @param options Object various switches you can send to this function
* + params: an object of key/value pairs to be sent to xsl as parameters
* + xpath: defines the root node within the provided xml file
* @returns Object the results of the transformation
* + xsl: the raw xsl doc
* + doc: the raw results of the transform
* + string: the serialized doc
*/
transform: function( xsl, xml, options ){
var log = { 'xsl':xsl, 'xml':xml, 'options':options };
if(this.debug) jQuery.log( 'transform(): ' + xsl + '::' + xml + '::' + options.toString() );
// initialize options hash
options = options || {};
// initialize the xml object and store it in xml.doc
var xml = { 'request':xml, 'doc':this.load(xml) };
// if we have an xpath, replace xml.doc with the results of running it
// as of 2007-12-03, IE throws a "msxml6: the parameter is incorrect" error, so removing this
if( options.xpath && xml.doc && !jQuery.browser.msie ){
// run the xpath
xml.doc = xml.doc.selectSingleNode( options.xpath.toString() );
if(this.debug) $.log( 'transform(): xpath has been run...resulting doc: ' + (this.serialize(xml.doc)) );
}
// initialize the result object ... store the primary steps of the transform in result
var result = { 'xsl':this.load(xsl) };
result.json = false;
if( options.json && xml.doc ) {
result.json = xml.doc.selectSingleNode( options.json.toString() );
}
var processor = new XSLTProcessor();
// stylesheet must be imported before parameters can be added
processor.importStylesheet( result.xsl );
// add parameters to the processor
if( options.params && processor ){
if(this.debug) jQuery.log( 'transform(): received xsl params: ' + options.params.toString() );
for( key in options.params ){
// name and value must be strings
// first parameter is namespace
processor.setParameter( null, key.toString(), options.params[key].toString() );
}
}
// perform the transformation
result.doc = processor.transformToDocument( xml.doc );
// handle transform error
var errorTxt = Sarissa.getParseErrorText(result.doc);
if(this.debug) jQuery.log( 'transform(): Sarissa parse text: ' + errorTxt );
if( errorTxt != Sarissa.PARSED_OK ){
// return the error text as the string
result.string = Sarissa.getParseErrorText(result.doc) + ' :: using ' + xsl + ' => ' + xml.request;
if(this.debug) jQuery.log( 'transform(): error in transformation: ' + Sarissa.getParseErrorText(result.doc) );
return result;
}
// if we made it this far, the transformation was successful
result.string = this.serialize( result.doc );
// store reference to all scripts found in the doc (not result.string)
result.scripts = jQuery('script',result.doc).text();
return result;
}
};
// create the xslTransform object
// this creates a single object for the page, allowing re-use of the XSL processor
xslTransform.init();
/*
* JQuery XSLT transformation plugin.
* Replaces all matched elements with the results of an XSLT transformation.
* See xslTransform above for more documentation.
*
* @example
* @desc See the xslTransform-example/index.html
*
* @param xsl String the url to the xsl file
* @param xml String the url to the xml file
* @param options Object various switches you can send to this function
* + params: an object of key/value pairs to be sent to xsl as parameters
* + xpath: defines the root node within the provided xml file
* + eval: if true, will attempt to eval javascript found in the transformed result
* + callback: if a Function, evaluate it when transformation is complete
* @returns
*/
jQuery.fn.getTransform = function( xsl, xml, options ){
var settings = {
append: false,
params: {}, // object of key/value pairs ... parameters to send to the XSL stylesheet
xpath: '', // xpath, used to send only a portion of the XML file to the XSL stylesheet
eval: true, // evaluate