add parse method to handle strings and buffers

This commit is contained in:
Sai1919
2016-11-15 18:09:07 +05:30
parent 46500c11ca
commit 6e29f884e4
3 changed files with 177 additions and 46 deletions

View File

@@ -13,8 +13,7 @@ npm install xml-streamer
## Basic Usage
`xml-streamer can be used in three
ways`
`xml-streamer can be used in four ways`
```javascript
@@ -109,6 +108,22 @@ npm install xml-streamer
})
}())
// 4. By passing a string or buffer to parse function
(function () {
"use strict";
var Parser = require('xml-streamer')
var opts = {resourcePath: '/items/item'} // resourcePath is manditory when using parse method
var parser = new Parser(opts)
parser.parse(stringOrBuffer, function (err, data) {
// consume data here
})
}())
```
## API

121
parser.js
View File

@@ -31,13 +31,53 @@ XmlParser.prototype.checkForInterestedNodeListeners = function () {
XmlParser.prototype._transform = function (chunk, encoding, callback) {
if (encoding !== 'buffer') this.emit('error', new Error('unsupported encoding'))
if (this.parserState.isRootNode) this.checkForInterestedNodeListeners()
this.parse(chunk)
this.processChunk(chunk)
callback()
}
XmlParser.prototype.parse = function (chunk) {
XmlParser.prototype.processChunk = function (chunk) {
var parser = this.parser
var state = this.parserState
if (state.isRootNode) {
this.checkForInterestedNodeListeners()
registerEvents.call(this)
}
if (typeof chunk === 'string') {
if (!parser.parse('', true)) processError.call(this)
} else {
if (!parser.parse(chunk.toString())) processError.call(this)
}
}
XmlParser.prototype.parse = function (chunk, cb) {
var parser = this.parser
var state = this.parserState
var error
if (state.isRootNode) {
this.checkForInterestedNodeListeners()
registerEvents.call(this)
}
if (typeof chunk === Buffer) chunk = chunk.toString()
this.on('error', function (err) {
error = err
})
if (!parser.parse(chunk)) {
error = processError.call(this)
}
if (error) return cb(error)
return cb(null, this._readableState.buffer)
}
function registerEvents () {
var scope = this
var parser = this.parser
var state = this.parserState
@@ -47,49 +87,28 @@ XmlParser.prototype.parse = function (chunk) {
var textKey = this.opts.textKey
var interestedNodes = state.interestedNodes
if (state.isRootNode) registerEvents()
parser.on('startElement', function (name, attrs) {
if (state.isRootNode) validateResourcePath(name)
state.currentPath = state.currentPath + '/' + name
checkForResourcePath(name)
if (state.isPathfound) processStartElement(name, attrs)
})
if (typeof chunk === 'string') {
if (!parser.parse('', true)) processError()
} else {
if (!parser.parse(chunk.toString())) processError()
}
parser.on('endElement', function (name) {
state.lastEndedNode = name
lastIndex = state.currentPath.lastIndexOf('/' + name)
state.currentPath = state.currentPath.substring(0, lastIndex)
if (state.isPathfound) processEndElement(name)
checkForResourcePath(name)
})
function registerEvents () {
parser.on('startElement', function (name, attrs) {
if (state.isRootNode) validateResourcePath(name)
state.currentPath = state.currentPath + '/' + name
checkForResourcePath(name)
if (state.isPathfound) processStartElement(name, attrs)
})
parser.on('text', function (text) {
if (state.isPathfound) processText(text)
})
parser.on('endElement', function (name) {
state.lastEndedNode = name
lastIndex = state.currentPath.lastIndexOf('/' + name)
state.currentPath = state.currentPath.substring(0, lastIndex)
if (state.isPathfound) processEndElement(name)
checkForResourcePath(name)
})
parser.on('text', function (text) {
if (state.isPathfound) processText(text)
})
parser.on('error', function (err) {
processError(err)
})
}
function processError (err) {
var error = ''
if (err) {
error = err
} else {
error = parser.getError()
}
scope.emit('error', new Error(error + ' at line no: ' + parser.getCurrentLineNumber()))
}
parser.on('error', function (err) {
processError.call(this, err)
})
function processStartElement (name, attrs) {
if (!name) return
@@ -243,8 +262,22 @@ XmlParser.prototype.parse = function (chunk) {
}
}
function processError (err) {
var parser = this.parser
var error = ''
if (err) {
error = err
} else {
error = parser.getError()
}
error = new Error(error + ' at line no: ' + parser.getCurrentLineNumber())
this.emit('error', error)
return error
}
XmlParser.prototype._flush = function (callback) {
this.parse('', true)
this.processChunk('')
callback()
}

View File

@@ -1227,4 +1227,87 @@ describe('Tests', function () {
xmlStream.pipe(parser)
})
})
describe('Parse funtion should work properly', function () {
it('should properly parse a simple file.', function (done) {
var xml = fs.readFileSync('./test/TestFiles/item.xml')
var parser = new ParserFactory({resourcePath: '/items/item'})
var expectedData = [
{ '$': { id: '1', test: 'hello' },
subitem:
[ { '$': { sub: 'TESTING SUB' }, _: 'one' },
{ '$': { sub: '2' }, _: 'two' } ] },
{ '$': { id: '2' },
subitem: [ { _: 'three' }, { _: 'four' }, { _: 'five' } ] } ]
parser.parse(xml.toString(), function (err, data) {
if (err) done(err)
data.should.deepEqual(expectedData)
done()
})
})
it('should properly parse a medium size file.', function (done) {
var xml = fs.readFileSync('./test/TestFiles/medium.xml')
var parser = new ParserFactory({resourcePath: '/items/item'})
parser.parse(xml, function (err, data) {
if (err) done(err)
data.length.should.equal(10)
done()
})
})
it('should properly parse a file containing many nodes.', function (done) {
var xml = fs.readFileSync('./test/TestFiles/manyItems.xml')
var parser = new ParserFactory({resourcePath: '/items/item'})
parser.parse(xml, function (err, data) {
if (err) done(err)
data.length.should.equal(296)
done()
})
})
it('should properly parse a xml simple file in which nodes contain text values randomly.', function (done) {
var xml = fs.readFileSync('./test/TestFiles/randomText.xml')
var parser = new ParserFactory({resourcePath: '/items/item'})
var expectedData = [ { '$': { 'id': '1', 'test': 'hello' }, '_': ' item one two',
'subitem': [ { '$': { 'sub': 'TESTING SUB' }, '_': 'one' },
{ '$': { 'sub': '2' }, '_': 'two' } ] },
{ '$': { 'id': '2' }, '_': ' item one two three four',
'subitem': [ { '_': 'three' }, { '_': 'four' }, { '_': 'five' } ] }
]
parser.parse(xml, function (err, data) {
if (err) done(err)
data.should.deepEqual(expectedData)
data.length.should.equal(2)
done()
})
})
it('should properly parse a huge file.', function (done) {
var xml = fs.readFileSync('./test/TestFiles/hugeFile.xml')
var parser = new ParserFactory({resourcePath: '/items/item'})
// console.log(parser)
parser.parse(xml, function (err, data) {
if (err) done(err)
data.length.should.equal(2072)
done()
})
})
it('should properly return error if the xml file is corrupted.', function (done) {
var xml = fs.readFileSync('./test/TestFiles/corrupted.xml')
var parser = new ParserFactory({resourcePath: '/items/item'})
parser.parse(xml, function (err, data) {
// console.log(err)
err.message.should.equal('mismatched tag at line no: 11')
should(data).not.be.ok()
done()
})
})
})
})