From c7df57cd647083a9a100c42c21466e6838c5face Mon Sep 17 00:00:00 2001 From: Max Kramer Date: Mon, 12 Feb 2018 20:26:36 -0500 Subject: [PATCH] Add parseStringSync Create a sync version of parseString to API to permit calling without a callback. The current implemenation is sync due to underlying implementation of SAX parser. Examples: ```js // Via root API var result = xml2js.parseStringSync('< ... >', options) // Via parser var parser = new xml2js.Parser(options); var result = parser.parseStringSync('< ... >'); ``` See #241 by @nobodyman See #319 by @mrparkers --- README.md | 20 ++++++++++++++++++ lib/parser.js | 25 +++++++++++++++++++++++ lib/xml2js.js | 2 ++ package.json | 4 +++- src/parser.coffee | 22 +++++++++++++++++++- src/xml2js.coffee | 1 + test/parser.test.coffee | 45 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 117 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ebf80ac..83a12e77 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,26 @@ 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! +Synchronous usage +------------------ + +Forced into a sync use-case? Use the `parseStringSync` method to execute parsing +in a synchronous manner. Failures will result in an thrown error. + +```javascript +var fs = require('fs'), + xml2js = require('xml2js'); + +var data = fs.readFileSync(__dirname + '/foo.xml', 'utf8'); + +// With parser +var parser = new xml2js.Parser(/* options */); +var result = parser.parseStringSync(data); + +// Without parser +var result = xml2js.parseStringSync(data /*, options */); +``` + Parsing multiple files ---------------------- diff --git a/lib/parser.js b/lib/parser.js index 9e8261eb..12e5f552 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -35,6 +35,7 @@ extend(Parser, superClass); function Parser(opts) { + this.parseStringSync = bind(this.parseStringSync, this); this.parseString = bind(this.parseString, this); this.reset = bind(this.reset, this); this.assignOrPush = bind(this.assignOrPush, this); @@ -331,6 +332,21 @@ } }; + Parser.prototype.parseStringSync = function(str) { + var cb, err, result; + result = void 0; + err = void 0; + cb = function(_err, _result) { + result = _result; + return err = _err; + }; + this.parseString(str, cb); + if (err) { + throw err; + } + return result; + }; + return Parser; })(events.EventEmitter); @@ -354,4 +370,13 @@ return parser.parseString(str, cb); }; + exports.parseStringSync = function(str, a) { + var options, parser; + if (typeof a === 'object') { + options = a; + } + parser = new exports.Parser(options); + return parser.parseStringSync(str); + }; + }).call(this); diff --git a/lib/xml2js.js b/lib/xml2js.js index 599d3dd2..7f07c9b1 100644 --- a/lib/xml2js.js +++ b/lib/xml2js.js @@ -34,4 +34,6 @@ exports.parseString = parser.parseString; + exports.parseStringSync = parser.parseStringSync; + }).call(this); diff --git a/package.json b/package.json index 33b53ec7..a0e7f2d9 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", diff --git a/src/parser.coffee b/src/parser.coffee index 8a375197..386a23cd 100644 --- a/src/parser.coffee +++ b/src/parser.coffee @@ -253,6 +253,20 @@ class exports.Parser extends events.EventEmitter else if @saxParser.ended throw err + parseStringSync: (str) => + # SAX events block when given a string instead of a stream + result = undefined + err = undefined + cb = (_err, _result) -> + result = _result + err = _err + + # parseString will implicitly call cb (thus setting closure result) before returning + @parseString str, cb + if err + throw err + result + exports.parseString = (str, a, b) -> # let's determine what we got as arguments if b? @@ -267,6 +281,12 @@ exports.parseString = (str, a, b) -> # and options should be empty - default options = {} - # the rest is super-easy parser = new exports.Parser options parser.parseString str, cb + +exports.parseStringSync = (str, a) -> + if typeof a == 'object' + options = a + + parser = new exports.Parser options + parser.parseStringSync str diff --git a/src/xml2js.coffee b/src/xml2js.coffee index a9b1b270..41538a10 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.parseStringSync = parser.parseStringSync diff --git a/test/parser.test.coffee b/test/parser.test.coffee index 6d531d56..ca61c464 100644 --- a/test/parser.test.coffee +++ b/test/parser.test.coffee @@ -574,3 +574,48 @@ module.exports = console.log 'Result object: ' + util.inspect r, false, 10 equ r.hasOwnProperty('SAMP'), true equ r.SAMP.hasOwnProperty('TAGN'), true) + + 'test sync parsing': (test) -> + x2js = new xml2js.Parser() + data = fs.readFileSync fileName, 'utf8' + r = x2js.parseStringSync data + assert.notEqual r, null + equ r.sample.listtest[0].item[0].subitem[0], 'Foo(1)' + test.finish() + + 'test sync with bad input': (test) -> + x2js = new xml2js.Parser() + data = fs.readFileSync fileName, 'utf8' + err = null + try + r = x2js.parseStringSync "< a moose bit my sister>"; + catch _err + err = _err + assert.notEqual err, null + test.finish() + + 'test global sync parsing': (test) -> + data = fs.readFileSync fileName, 'utf8' + r = xml2js.parseStringSync data + assert.notEqual r, null + equ r.sample.listtest[0].item[0].subitem[0], 'Foo(1)' + test.finish() + + 'test global sync parsing with options': (test) -> + data = fs.readFileSync fileName, 'utf8' + r = xml2js.parseStringSync data, + trim: true + normalize: true + console.log r + equ r.sample.whitespacetest[0]._, 'Line One Line Two' + test.finish() + + 'test global sync with bad input': (test) -> + data = fs.readFileSync fileName, 'utf8' + err = null + try + r = xml2js.parseStringSync "< a moose bit my sister>"; + catch _err + err = _err + assert.notEqual err, null + test.finish()