From 6353f53d54016bcda1ed9cf83bd73407e6602dd6 Mon Sep 17 00:00:00 2001 From: Max Kramer Date: Mon, 12 Feb 2018 21:59:16 -0500 Subject: [PATCH] Create a promise-specific version of parseString Examples: ```js // Via root API xml2js.parseStringPromise('< ... >', options) .then(function (result) { /* ... */ }) .catch(function (err) { /* ... */ }) // Via parser var parser = new xml2js.Parser(options); parser.parseStringPromise('< ... >') .then(function (result) { /* ... */ }) .catch(function (err) { /* ... */ }) ``` --- README.md | 27 +++++++++++++++++++++ lib/parser.js | 18 +++++++++++++- lib/xml2js.js | 2 ++ package.json | 5 +++- src/parser.coffee | 11 +++++++++ src/xml2js.coffee | 1 + test/parser.test.coffee | 52 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 114 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be7b83f4..0d55942c 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,33 @@ not, we got you covered! Starting with 0.2.8 you can also leave it out, in which case `xml2js` will helpfully add it for you, no bad surprises and inexplicable bugs! +Promise usage +------------- + +```javascript +var xml2js = require('xml2js'); +var xml = ''; + +// With parser +var parser = new xml2js.Parser(/* options */); +parser.parseStringPromise(data).then(function (result) { + console.dir(result); + console.log('Done'); +}) +.catch(function (err) { + // Failed +}); + +// Without parser +xml2js.parseStringPromise(data /*, options */).then(function (result) { + console.dir(result); + console.log('Done'); +}) +.catch(function (err) { + // Failed +}); +``` + Parsing multiple files ---------------------- diff --git a/lib/parser.js b/lib/parser.js index 9e8261eb..0ce9ecc0 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript 1.12.7 (function() { "use strict"; - var bom, defaults, events, isEmpty, processItem, processors, sax, setImmediate, + var bom, defaults, events, isEmpty, processItem, processors, promisify, sax, setImmediate, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; @@ -10,6 +10,8 @@ events = require('events'); + promisify = require('util.promisify'); + bom = require('./bom'); processors = require('./processors'); @@ -35,6 +37,7 @@ extend(Parser, superClass); function Parser(opts) { + this.parseStringPromise = bind(this.parseStringPromise, this); this.parseString = bind(this.parseString, this); this.reset = bind(this.reset, this); this.assignOrPush = bind(this.assignOrPush, this); @@ -331,6 +334,10 @@ } }; + Parser.prototype.parseStringPromise = function(str) { + return promisify(this.parseString)(str); + }; + return Parser; })(events.EventEmitter); @@ -354,4 +361,13 @@ return parser.parseString(str, cb); }; + exports.parseStringPromise = function(str, a) { + var options, parser; + if (typeof a === 'object') { + options = a; + } + parser = new exports.Parser(options); + return parser.parseStringPromise(str); + }; + }).call(this); diff --git a/lib/xml2js.js b/lib/xml2js.js index 599d3dd2..24b6e699 100644 --- a/lib/xml2js.js +++ b/lib/xml2js.js @@ -34,4 +34,6 @@ exports.parseString = parser.parseString; + exports.parseStringPromise = parser.parseStringPromise; + }).call(this); diff --git a/package.json b/package.json index 590d4cee..e3e9264e 100644 --- a/package.json +++ b/package.json @@ -63,9 +63,11 @@ "lib": "./lib" }, "scripts": { + "build": "cake build", "test": "zap", "coverage": "nyc npm test && nyc report", - "coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls" + "coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls", + "doc": "cake doc" }, "repository": { "type": "git", @@ -73,6 +75,7 @@ }, "dependencies": { "sax": ">=0.6.0", + "util.promisify": "~1.0.0", "xmlbuilder": "~9.0.1" }, "devDependencies": { diff --git a/src/parser.coffee b/src/parser.coffee index 8a375197..de5c3de1 100644 --- a/src/parser.coffee +++ b/src/parser.coffee @@ -2,6 +2,7 @@ sax = require 'sax' events = require 'events' +promisify = require 'util.promisify' bom = require './bom' processors = require './processors' setImmediate = require('timers').setImmediate @@ -253,6 +254,9 @@ class exports.Parser extends events.EventEmitter else if @saxParser.ended throw err + parseStringPromise: (str) => + promisify(@parseString) str + exports.parseString = (str, a, b) -> # let's determine what we got as arguments if b? @@ -270,3 +274,10 @@ exports.parseString = (str, a, b) -> # the rest is super-easy parser = new exports.Parser options parser.parseString str, cb + +exports.parseStringPromise = (str, a) -> + if typeof a == 'object' + options = a + + parser = new exports.Parser options + parser.parseStringPromise str diff --git a/src/xml2js.coffee b/src/xml2js.coffee index a9b1b270..57321585 100644 --- a/src/xml2js.coffee +++ b/src/xml2js.coffee @@ -18,3 +18,4 @@ exports.Builder = builder.Builder exports.Parser = parser.Parser exports.parseString = parser.parseString +exports.parseStringPromise = parser.parseStringPromise diff --git a/test/parser.test.coffee b/test/parser.test.coffee index 6d531d56..ac9ed47e 100644 --- a/test/parser.test.coffee +++ b/test/parser.test.coffee @@ -5,9 +5,12 @@ util = require 'util' assert = require 'assert' path = require 'path' os = require 'os' +promisify = require 'util.promisify' fileName = path.join __dirname, '/fixtures/sample.xml' +readFilePromise = promisify fs.readFile + skeleton = (options, checks) -> (test) -> xmlString = options?.__xmlString @@ -574,3 +577,52 @@ module.exports = console.log 'Result object: ' + util.inspect r, false, 10 equ r.hasOwnProperty('SAMP'), true equ r.SAMP.hasOwnProperty('TAGN'), true) + + + 'test parseStringPromise parsing': (test) -> + x2js = new xml2js.Parser() + readFilePromise(fileName).then (data) -> + x2js.parseStringPromise data + .then (r) -> + # just a single test to check whether we parsed anything + equ r.sample.chartest[0]._, 'Character data here!' + test.finish() + .catch (err) -> + test.fail('Should not error') + + 'test parseStringPromise with bad input': (test) -> + x2js = new xml2js.Parser() + x2js.parseStringPromise("< a moose bit my sister>").then (r) -> + test.fail('Should fail') + .catch (err) -> + assert.notEqual err, null + test.finish() + + 'test global parseStringPromise parsing': (test) -> + readFilePromise(fileName).then (data) -> + xml2js.parseStringPromise data + .then (r) -> + assert.notEqual r, null + equ r.sample.listtest[0].item[0].subitem[0], 'Foo(1)' + test.finish() + .catch (err) -> + test.fail('Should not error') + + 'test global parseStringPromise with options': (test) -> + readFilePromise(fileName).then (data) -> + xml2js.parseStringPromise data, + trim: true + normalize: true + .then (r) -> + assert.notEqual r, null + equ r.sample.whitespacetest[0]._, 'Line One Line Two' + test.finish() + .catch (err) -> + test.fail('Should not error') + + 'test global parseStringPromise with bad input': (test) -> + xml2js.parseStringPromise("< a moose bit my sister>").then (r) -> + test.fail('Should fail') + .catch (err) -> + assert.notEqual err, null + test.finish()