Comparing version 0.1.5 to 0.2.0
@@ -23,3 +23,3 @@ var fs = require('fs'); | ||
var stylesheetParsingStr = function(iterations, callback) { | ||
var stylesheetSyncParsingStr = function(iterations, callback) { | ||
for (var i = 0; i < iterations; i++) { | ||
@@ -31,3 +31,3 @@ libxslt.parse(stylesheetStr); | ||
var stylesheetParsingObj = function(iterations, callback) { | ||
var stylesheetSyncParsingObj = function(iterations, callback) { | ||
for (var i = 0; i < iterations; i++) { | ||
@@ -39,2 +39,42 @@ libxslt.parse(stylesheetObj); | ||
var stylesheetAsyncSeriesParsingStr = function(iterations, callback) { | ||
var i = 0; | ||
async.eachSeries(new Array(iterations), function(u, callbackEach) { | ||
libxslt.parse(stylesheetStr, function(err, result) { | ||
i++; | ||
callbackEach(err); | ||
}); | ||
}, callback); | ||
}; | ||
var stylesheetAsyncSeriesParsingObj = function(iterations, callback) { | ||
var i = 0; | ||
async.eachSeries(new Array(iterations), function(u, callbackEach) { | ||
libxslt.parse(stylesheetObj, function(err, result) { | ||
i++; | ||
callbackEach(err); | ||
}); | ||
}, callback); | ||
}; | ||
var stylesheetAsyncParallelParsingStr = function(iterations, callback) { | ||
var i = 0; | ||
async.eachLimit(new Array(iterations), 10, function(u, callbackEach) { | ||
libxslt.parse(stylesheetStr, function(err, result) { | ||
i++; | ||
callbackEach(err); | ||
}); | ||
}, callback); | ||
}; | ||
var stylesheetAsyncParallelParsingObj = function(iterations, callback) { | ||
var i = 0; | ||
async.eachLimit(new Array(iterations), 10, function(u, callbackEach) { | ||
libxslt.parse(stylesheetObj, function(err, result) { | ||
i++; | ||
callbackEach(err); | ||
}); | ||
}, callback); | ||
}; | ||
var applySyncStr = function(iterations, callback) { | ||
@@ -96,10 +136,19 @@ for (var i = 0; i < iterations; i++) { | ||
async.series([ | ||
//bench('stylesheet parsing from string\t\t\t', iterations, stylesheetParsingStr), | ||
//bench('stylesheet parsing from parsed doc\t\t\t', iterations, stylesheetParsingObj), | ||
//bench('synchronous parse from string\t\t\t', iterations, stylesheetSyncParsingStr), | ||
bench('synchronous parse from parsed doc\t\t\t', iterations, stylesheetSyncParsingObj), | ||
//bench('asynchronous parse in series from string\t\t\t', iterations, stylesheetAsyncSeriesParsingStr), | ||
bench('asynchronous parse in series from parsed doc\t', iterations, stylesheetAsyncSeriesParsingObj), | ||
//bench('asynchronous parse in parallel from string\t\t\t', iterations, stylesheetAsyncParallelParsingStr), | ||
bench('asynchronous parse in parallel from parsed doc\t', iterations, stylesheetAsyncParallelParsingObj), | ||
//bench('synchronous apply from string\t\t\t', iterations, applySyncStr), | ||
bench('synchronous apply from parsed doc\t\t\t', iterations, applySyncObj), | ||
//bench('asynchronous apply in series from string\t\t', iterations, applyAsyncSeriesStr), | ||
bench('asynchronous apply in series from parsed doc\t', iterations, applyAsyncSeriesObj), | ||
//bench('asynchronous apply in parallel from string\t', iterations, applyAsyncParallelStr), | ||
bench('asynchronous apply in parallel from parsed doc\t', iterations, applyAsyncParallelObj) | ||
]); |
121
index.js
@@ -0,11 +1,90 @@ | ||
/** | ||
* Node.js bindings for libxslt compatible with libxmljs | ||
* @module libxslt | ||
*/ | ||
var fs = require('fs'); | ||
var libxmljs = require('libxmljs'); | ||
//var binding = require('./build/Debug/node-libxslt'); | ||
var binding = require('bindings')('node-libxslt'); | ||
/** | ||
* A compiled stylesheet. Do not call this constructor, instead use parse or parseFile. | ||
* | ||
* store both the source document and the parsed stylesheet | ||
* if we don't store the stylesheet doc it will be deleted by garbage collector and it will result in segfaults. | ||
* | ||
* @constructor | ||
* @param {Document} stylesheetDoc - XML document source of the stylesheet | ||
* @param {Document} stylesheetObj - Simple wrapper of a libxslt stylesheet | ||
*/ | ||
var Stylesheet = function(stylesheetDoc, stylesheetObj){ | ||
// store both the source document and the parsed stylesheet | ||
// if we don't store the stylesheet doc it will be deleted by garbage collector and it will result in segfaults. | ||
this.stylesheetDoc = stylesheetDoc; | ||
this.stylesheetObj = stylesheetObj; | ||
}; | ||
/** | ||
* Parse a XSL stylesheet | ||
* | ||
* If no callback is given the function will run synchronously and return the result or throw an error. | ||
* | ||
* @param {string|Document} source - The content of the stylesheet as a string or a [libxmljs document]{@link https://github.com/polotek/libxmljs/wiki/Document} | ||
* @param {parseCallback} [callback] - The callback that handles the response. Expects err and Stylesheet object. | ||
* @return {Stylesheet} Only if no callback is given. | ||
*/ | ||
exports.parse = function(source, callback) { | ||
// stylesheet can be given as a string or a pre-parsed xml document | ||
if (typeof source === 'string') { | ||
try { | ||
source = libxmljs.parseXml(source); | ||
} catch (err) { | ||
if (callback) return callback(err); | ||
throw err; | ||
} | ||
} | ||
if (callback) { | ||
binding.stylesheetAsync(source, function(err, stylesheet){ | ||
if (err) return callback(err); | ||
callback(null, new Stylesheet(source, stylesheet)); | ||
}); | ||
} else { | ||
return new Stylesheet(source, binding.stylesheetSync(source)); | ||
} | ||
}; | ||
/** | ||
* Callback to the parse function | ||
* @callback parseCallback | ||
* @param {error} [err] | ||
* @param {Stylesheet} [stylesheet] | ||
*/ | ||
/** | ||
* Parse a XSL stylesheet | ||
* | ||
* @param {stringPath} sourcePath - The path of the file | ||
* @param {parseFileCallback} callback - The callback that handles the response. Expects err and Stylesheet object. | ||
*/ | ||
exports.parseFile = function(sourcePath, callback) { | ||
fs.readFile(sourcePath, 'utf8', function(err, data){ | ||
if (err) return callback(err); | ||
exports.parse(data, callback); | ||
}); | ||
}; | ||
/** | ||
* Callback to the parseFile function | ||
* @callback parseFileCallback | ||
* @param {error} [err] | ||
* @param {Stylesheet} [stylesheet] | ||
*/ | ||
/** | ||
* Apply a stylesheet to a XML document | ||
* | ||
* If no callback is given the function will run synchronously and return the result or throw an error. | ||
* | ||
* @param {string|Document} source - The XML content to apply the stylesheet to given as a string or a [libxmljs document]{@link https://github.com/polotek/libxmljs/wiki/Document} | ||
* @param {object} [params] - Parameters passed to the stylesheet ({@link http://www.w3schools.com/xsl/el_with-param.asp}) | ||
* @param {Stylesheet~applyCallback} [callback] - The callback that handles the response. Expects err and result of the same type as the source param passed to apply. | ||
* @return {string|Document} Only if no callback is given. Type is the same as the source param. | ||
*/ | ||
Stylesheet.prototype.apply = function(source, params, callback) { | ||
@@ -57,12 +136,28 @@ // params are optional | ||
}; | ||
/** | ||
* Callback to the Stylesheet.apply function | ||
* @callback Stylesheet~applyCallback | ||
* @param {error} [err] - Error either from parsing the XML document if given as a string or from applying the styleshet | ||
* @param {string|Document} [result] Result of the same type as the source param passed to apply | ||
*/ | ||
exports.parse = function(source, callback) { | ||
// stylesheet can be given as a string or a pre-parsed xml document | ||
if (typeof source === 'string') source = libxmljs.parseXml(source); | ||
if (callback) { | ||
//return binding.stylesheetAsync(source); | ||
} else { | ||
return new Stylesheet(source, binding.stylesheetSync(source)); | ||
} | ||
}; | ||
/** | ||
* Apply a stylesheet to a XML file | ||
* | ||
* @param {string} sourcePath - The path of the file to read | ||
* @param {object} [params] - Parameters passed to the stylesheet ({@link http://www.w3schools.com/xsl/el_with-param.asp}) | ||
* @param {Stylesheet~applyToFileCallback} callback The callback that handles the response. Expects err and result as string. | ||
*/ | ||
Stylesheet.prototype.applyToFile = function(sourcePath, params, callback) { | ||
var that = this; | ||
fs.readFile(sourcePath, 'utf8', function(err, data){ | ||
if (err) return callback(err); | ||
that.apply(data, params, callback); | ||
}); | ||
}; | ||
/** | ||
* Callback to the Stylesheet.applyToFile function | ||
* @callback Stylesheet~applyToFileCallback | ||
* @param {error} [err] - Error either from reading the file, parsing the XML document or applying the styleshet | ||
* @param {string} [result] | ||
*/ |
{ | ||
"name": "libxslt", | ||
"version": "0.1.5", | ||
"version": "0.2.0", | ||
"description": "Node.js bindings for libxslt compatible with libxmljs", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha -R spec" | ||
"test": "mocha -R spec", | ||
"docs": "jsdoc2md index.js --template readme.hbs > README.md" | ||
}, | ||
@@ -27,11 +28,12 @@ "keywords": [ | ||
"dependencies": { | ||
"nan": "~1.2.0", | ||
"libxmljs": "~0.11.1", | ||
"bindings": "~1.2.1" | ||
"bindings": "~1.2.1", | ||
"libxmljs": "^0.11.1", | ||
"nan": "~1.2.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "~1.21.0", | ||
"should": "~4.0.4", | ||
"async": "~0.9.0" | ||
"async": "~0.9.0", | ||
"jsdoc-to-markdown": "^0.5.7", | ||
"mocha": "^1.21.4", | ||
"should": "~4.0.4" | ||
} | ||
} |
125
README.md
@@ -21,14 +21,13 @@ node-libxslt | ||
var stylesheet = libxslt.parse(stylesheetString); | ||
libxslt.parse(stylesheetString, function(err, stylesheet){ | ||
var params = { | ||
MyParam: 'my value' | ||
}; | ||
var params = { | ||
MyParam: 'my value' | ||
}; | ||
// 'params' parameter is optional | ||
stylesheet.apply(documentString, params, function(err, result){ | ||
// err contains any error from parsing the document or applying the stylesheet | ||
// result is a string containing the result of the transformation | ||
// 'params' parameter is optional | ||
stylesheet.apply(documentString, params, function(err, result){ | ||
// err contains any error from parsing the document or applying the stylesheet | ||
// result is a string containing the result of the transformation | ||
}); | ||
}); | ||
``` | ||
@@ -61,6 +60,13 @@ | ||
Includes | ||
-------- | ||
XSL includes are supported but relative paths must be given from the execution directory, usually the root of the project. | ||
Includes are resolved when parsing the stylesheet by libxml. Therefore the parsing task becomes IO bound, which is why you should not use synchronous parsing when you expect some includes. | ||
Sync or async | ||
------------- | ||
The same *apply()* function can be used in synchronous mode simply by removing the callback parameter. | ||
The same *parse()* and *apply()* functions can be used in synchronous mode simply by removing the callback parameter. | ||
In this case if a parsing error occurs it will be thrown. | ||
@@ -77,3 +83,3 @@ | ||
The asynchronous function uses the [libuv work queue](http://nikhilm.github.io/uvbook/threads.html#libuv-work-queue) | ||
The asynchronous functions use the [libuv work queue](http://nikhilm.github.io/uvbook/threads.html#libuv-work-queue) | ||
to provide parallelized computation in node.js worker threads. This makes it non-blocking for the main event loop of node.js. | ||
@@ -91,5 +97,9 @@ | ||
``` | ||
10000 synchronous apply from parsed doc in 331ms = 30211/s | ||
10000 asynchronous apply in series from parsed doc in 538ms = 18587/s | ||
10000 asynchronous apply in parallel from parsed doc in 217ms = 46083/s | ||
10000 synchronous parse from parsed doc in 52ms = 192308/s | ||
10000 asynchronous parse in series from parsed doc in 229ms = 43668/s | ||
10000 asynchronous parse in parallel from parsed doc in 56ms = 178571/s | ||
10000 synchronous apply from parsed doc in 329ms = 30395/s | ||
10000 asynchronous apply in series from parsed doc in 569ms = 17575/s | ||
10000 asynchronous apply in parallel from parsed doc in 288ms = 34722/s | ||
``` | ||
@@ -106,2 +116,3 @@ | ||
- of course you can also use synchronous simply to reduce code depth. If you don't expect a huge load it will be ok. | ||
- DO NOT USE synchronous parsing if there is some includes in your XSL stylesheets. | ||
@@ -113,2 +124,84 @@ Environment compatibility | ||
Node-libxslt depends on [node-gyp](https://github.com/TooTallNate/node-gyp), you will need to meet its requirements. This can be a bit painful mostly for windows users. The node-gyp version bundled in your npm will have to be greater than 0.13.0, so you might have to follow [these instructions to upgrade](https://github.com/TooTallNate/node-gyp/wiki/Updating-npm's-bundled-node-gyp). There is no system dependancy otherwise, libxslt is bundled in the project. | ||
Node-libxslt depends on [node-gyp](https://github.com/TooTallNate/node-gyp), you will need to meet its requirements. This can be a bit painful mostly for windows users. The node-gyp version bundled in your npm will have to be greater than 0.13.0, so you might have to follow [these instructions to upgrade](https://github.com/TooTallNate/node-gyp/wiki/Updating-npm's-bundled-node-gyp). There is no system dependancy otherwise, libxslt is bundled in the project. | ||
API Reference | ||
============= | ||
Node.js bindings for libxslt compatible with libxmljs | ||
**Members** | ||
* [libxslt](#module_libxslt) | ||
* [libxslt.parse(source, [callback])](#module_libxslt.parse) | ||
* [libxslt.parseFile(sourcePath, callback)](#module_libxslt.parseFile) | ||
* [class: libxslt~Stylesheet](#module_libxslt..Stylesheet) | ||
* [new libxslt~Stylesheet(stylesheetDoc, stylesheetObj)](#new_module_libxslt..Stylesheet) | ||
* [stylesheet.apply(source, [params], [callback])](#module_libxslt..Stylesheet#apply) | ||
* [stylesheet.applyToFile(sourcePath, [params], callback)](#module_libxslt..Stylesheet#applyToFile) | ||
<a name="module_libxslt.parse"></a> | ||
##libxslt.parse(source, [callback]) | ||
Parse a XSL stylesheet | ||
If no callback is given the function will run synchronously and return the result or throw an error. | ||
**Params** | ||
- source `string` | `Document` - The content of the stylesheet as a string or a [libxmljs document](https://github.com/polotek/libxmljs/wiki/Document) | ||
- \[callback\] <code>[parseCallback](#parseCallback)</code> - The callback that handles the response. Expects err and Stylesheet object. | ||
**Returns**: `Stylesheet` - Only if no callback is given. | ||
<a name="module_libxslt.parseFile"></a> | ||
##libxslt.parseFile(sourcePath, callback) | ||
Parse a XSL stylesheet | ||
**Params** | ||
- sourcePath `stringPath` - The path of the file | ||
- callback <code>[parseFileCallback](#parseFileCallback)</code> - The callback that handles the response. Expects err and Stylesheet object. | ||
<a name="module_libxslt..Stylesheet"></a> | ||
##class: libxslt~Stylesheet | ||
**Members** | ||
* [class: libxslt~Stylesheet](#module_libxslt..Stylesheet) | ||
* [new libxslt~Stylesheet(stylesheetDoc, stylesheetObj)](#new_module_libxslt..Stylesheet) | ||
* [stylesheet.apply(source, [params], [callback])](#module_libxslt..Stylesheet#apply) | ||
* [stylesheet.applyToFile(sourcePath, [params], callback)](#module_libxslt..Stylesheet#applyToFile) | ||
<a name="new_module_libxslt..Stylesheet"></a> | ||
###new libxslt~Stylesheet(stylesheetDoc, stylesheetObj) | ||
A compiled stylesheet. Do not call this constructor, instead use parse or parseFile. | ||
store both the source document and the parsed stylesheet | ||
if we don't store the stylesheet doc it will be deleted by garbage collector and it will result in segfaults. | ||
**Params** | ||
- stylesheetDoc `Document` - XML document source of the stylesheet | ||
- stylesheetObj `Document` - Simple wrapper of a libxslt stylesheet | ||
**Scope**: inner class of [libxslt](#module_libxslt) | ||
<a name="module_libxslt..Stylesheet#apply"></a> | ||
###stylesheet.apply(source, [params], [callback]) | ||
Apply a stylesheet to a XML document | ||
If no callback is given the function will run synchronously and return the result or throw an error. | ||
**Params** | ||
- source `string` | `Document` - The XML content to apply the stylesheet to given as a string or a [libxmljs document](https://github.com/polotek/libxmljs/wiki/Document) | ||
- \[params\] `object` - Parameters passed to the stylesheet ([http://www.w3schools.com/xsl/el_with-param.asp](http://www.w3schools.com/xsl/el_with-param.asp)) | ||
- \[callback\] <code>[applyCallback](#Stylesheet..applyCallback)</code> - The callback that handles the response. Expects err and result of the same type as the source param passed to apply. | ||
**Returns**: `string` | `Document` - Only if no callback is given. Type is the same as the source param. | ||
<a name="module_libxslt..Stylesheet#applyToFile"></a> | ||
###stylesheet.applyToFile(sourcePath, [params], callback) | ||
Apply a stylesheet to a XML file | ||
**Params** | ||
- sourcePath `string` - The path of the file to read | ||
- \[params\] `object` - Parameters passed to the stylesheet ([http://www.w3schools.com/xsl/el_with-param.asp](http://www.w3schools.com/xsl/el_with-param.asp)) | ||
- callback <code>[applyToFileCallback](#Stylesheet..applyToFileCallback)</code> - The callback that handles the response. Expects err and result as string. | ||
*documented by [jsdoc-to-markdown](https://github.com/75lb/jsdoc-to-markdown)*. |
@@ -8,6 +8,6 @@ var fs = require('fs'); | ||
describe('node-libxslt bindings', function() { | ||
describe('node-libxslt', function() { | ||
var stylesheetSource; | ||
before(function(callback){ | ||
fs.readFile('./test/resources/cd.xsl', 'utf8', function(err, data){ | ||
before(function(callback) { | ||
fs.readFile('./test/resources/cd.xsl', 'utf8', function(err, data) { | ||
stylesheetSource = data; | ||
@@ -18,4 +18,4 @@ callback(err); | ||
var docSource; | ||
before(function(callback){ | ||
fs.readFile('./test/resources/cd.xml', 'utf8', function(err, data){ | ||
before(function(callback) { | ||
fs.readFile('./test/resources/cd.xml', 'utf8', function(err, data) { | ||
docSource = data; | ||
@@ -26,4 +26,21 @@ callback(err); | ||
var stylesheetIncludeSource; | ||
before(function(callback) { | ||
fs.readFile('./test/resources/xslinclude.xsl', 'utf8', function(err, data) { | ||
stylesheetIncludeSource = data; | ||
callback(err); | ||
}); | ||
}); | ||
var doc2Source; | ||
before(function(callback) { | ||
fs.readFile('./test/resources/collection.xml', 'utf8', function(err, data) { | ||
doc2Source = data; | ||
callback(err); | ||
}); | ||
}); | ||
var stylesheet; | ||
describe('stylesheet function', function() { | ||
var stylesheetInclude; | ||
describe('synchronous parse function', function() { | ||
it('should parse a stylesheet from a libxmljs xml document', function() { | ||
@@ -38,2 +55,7 @@ var stylesheetDoc = libxmljs.parseXml(stylesheetSource); | ||
}); | ||
it('should parse a stylesheet with a include from a xml string', function() { | ||
var stylesheetDoc = libxmljs.parseXml(stylesheetIncludeSource); | ||
stylesheetInclude = libxslt.parse(stylesheetDoc); | ||
stylesheetInclude.should.be.type('object'); | ||
}); | ||
it('should throw an error when parsing invalid stylesheet', function() { | ||
@@ -46,3 +68,42 @@ (function() { | ||
describe('Synchronous Stylesheet.apply function', function() { | ||
describe('parseFile function', function() { | ||
it('should parse a stylesheet from a file', function(callback) { | ||
libxslt.parseFile('./test/resources/cd.xsl', function(err, stylesheet) { | ||
console.log(err); | ||
stylesheet.should.be.type('object'); | ||
callback(err); | ||
}); | ||
}); | ||
}); | ||
describe('asynchronous parse function', function() { | ||
it('should parse a stylesheet from a libxmljs xml document', function(callback) { | ||
var stylesheetDoc = libxmljs.parseXml(stylesheetSource); | ||
libxslt.parse(stylesheetDoc, function(err, stylesheet) { | ||
stylesheet.should.be.type('object'); | ||
callback(err); | ||
}); | ||
}); | ||
it('should parse a stylesheet from a xml string', function(callback) { | ||
libxslt.parse(stylesheetSource, function(err, stylesheet) { | ||
stylesheet.should.be.type('object'); | ||
callback(err); | ||
}); | ||
}); | ||
it('should parse a stylesheet with a include from a xml string', function(callback) { | ||
var stylesheetDoc = libxmljs.parseXml(stylesheetIncludeSource); | ||
libxslt.parse(stylesheetDoc, function(err, stylesheet) { | ||
stylesheet.should.be.type('object'); | ||
callback(err); | ||
}); | ||
}); | ||
it('should return an error when parsing invalid stylesheet', function(callback) { | ||
libxslt.parse('this is not a stylesheet!', function(err) { | ||
should.exist(err); | ||
callback(); | ||
}); | ||
}); | ||
}); | ||
describe('synchronous apply function', function() { | ||
it('should apply a stylesheet to a libxmljs xml document', function() { | ||
@@ -60,13 +121,21 @@ var doc = libxmljs.parseXml(docSource); | ||
it('should apply a stylesheet with a parameter', function() { | ||
var result = stylesheet.apply(docSource, {MyParam: 'MyParamValue'}); | ||
var result = stylesheet.apply(docSource, { | ||
MyParam: 'MyParamValue' | ||
}); | ||
result.should.be.type('string'); | ||
result.should.match(/<p>My param: MyParamValue<\/p>/); | ||
}); | ||
it('should apply a stylesheet with a include to a xml string', function(callback) { | ||
stylesheetInclude.apply(doc2Source, function(err, result) { | ||
result.should.be.type('string'); | ||
result.should.match(/Title - Lover Birds/); | ||
callback(); | ||
}); | ||
}); | ||
}); | ||
// TODO Asynchronous implementation almost ok, but generates segfault. | ||
describe('Asynchronous Stylesheet.apply function', function() { | ||
describe('asynchronous apply function', function() { | ||
it('should apply a stylesheet to a libxmljs xml document', function(callback) { | ||
var doc = libxmljs.parseXml(docSource); | ||
stylesheet.apply(doc, function(err, result){ | ||
stylesheet.apply(doc, function(err, result) { | ||
result.should.be.type('object'); | ||
@@ -78,3 +147,3 @@ result.toString().should.match(/<td>Bob Dylan<\/td>/); | ||
it('should apply a stylesheet to a xml string', function(callback) { | ||
stylesheet.apply(docSource, function(err, result){ | ||
stylesheet.apply(docSource, function(err, result) { | ||
result.should.be.type('string'); | ||
@@ -86,3 +155,12 @@ result.should.match(/<td>Bob Dylan<\/td>/); | ||
}); | ||
describe('applyToFile function', function() { | ||
it('should apply a stylesheet to a xml file', function(callback) { | ||
stylesheet.applyToFile('./test/resources/cd.xml', function(err, result) { | ||
result.should.be.type('string'); | ||
result.should.match(/<td>Bob Dylan<\/td>/); | ||
callback(); | ||
}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1645705
162
922
201
4
4
Updatedlibxmljs@^0.11.1