From a03851fac3ec2d84c6ee16c14d057a7f14128969 Mon Sep 17 00:00:00 2001 From: Louis-Dominique Dubeau Date: Thu, 10 May 2018 14:39:40 -0400 Subject: [PATCH] Add an emitEmpty option. The option emitEmpty cause sax to emit `cdata` and `comment` events even if the respective constructs were empty in the XML. --- README.md | 3 +++ lib/sax.js | 8 ++++++-- test/emit_empty.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 test/emit_empty.js diff --git a/README.md b/README.md index afcd3f3d..283c9313 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,9 @@ Settings supported: * `strictEntities` - Boolean. If true, only parse [predefined XML entities](http://www.w3.org/TR/REC-xml/#sec-predefined-ent) (`&`, `'`, `>`, `<`, and `"`) +* `emitEmpty` - Boolean. If true, then SAX will emit `cdata` and `comment` + events even if the CDATA section or comment were empty. By default, + when these XML structures are empty, SAX does not emit an event. ## Methods diff --git a/lib/sax.js b/lib/sax.js index 795d607e..4b960b6a 100644 --- a/lib/sax.js +++ b/lib/sax.js @@ -61,6 +61,7 @@ parser.noscript = !!(strict || parser.opt.noscript) parser.state = S.BEGIN parser.strictEntities = parser.opt.strictEntities + parser.emitEmpty = parser.opt.emitEmpty parser.ENTITIES = parser.strictEntities ? Object.create(sax.XML_ENTITIES) : Object.create(sax.ENTITIES) parser.attribList = [] @@ -140,6 +141,9 @@ function flushBuffers (parser) { closeText(parser) + // We do not need to check emitEmpty here. We are guaranteed + // to produce a cdata event with an empty string when the cdata + // section ends. if (parser.cdata !== '') { emitNode(parser, 'oncdata', parser.cdata) parser.cdata = '' @@ -1180,7 +1184,7 @@ if (c === '-') { parser.state = S.COMMENT_ENDED parser.comment = textopts(parser.opt, parser.comment) - if (parser.comment) { + if (parser.emitEmpty || parser.comment) { emitNode(parser, 'oncomment', parser.comment) } parser.comment = '' @@ -1221,7 +1225,7 @@ case S.CDATA_ENDING_2: if (c === '>') { - if (parser.cdata) { + if (parser.emitEmpty || parser.cdata) { emitNode(parser, 'oncdata', parser.cdata) } emitNode(parser, 'onclosecdata') diff --git a/test/emit_empty.js b/test/emit_empty.js new file mode 100644 index 00000000..8c5bddb4 --- /dev/null +++ b/test/emit_empty.js @@ -0,0 +1,47 @@ +var xml = '' +require(__dirname).test({ + xml: xml, + expect: [ + ['opentagstart', {'name': 'R', 'attributes': {}}], + ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}], + ['opencdata', undefined], + ['closecdata', undefined], + ['closetag', 'R'] + ] +}) + +require(__dirname).test({ + xml: xml, + opt: { emitEmpty: true }, + expect: [ + ['opentagstart', {'name': 'R', 'attributes': {}}], + ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}], + ['opencdata', undefined], + ['cdata', ''], + ['closecdata', undefined], + ['comment', ''], + ['closetag', 'R'] + ] +}) + +// The following test illustrates an effect of emitEmpty together with +// hitting the buffer limit. Namely, a trailing cdata event with an +// empty string will be emitted after the buffer is emptied. +var sax = require('../lib/sax') +var bl = sax.MAX_BUFFER_LENGTH +sax.MAX_BUFFER_LENGTH = 10 +require(__dirname).test({ + opt: { emitEmpty: true }, + expect: [ + ['opentagstart', {'name': 'R', 'attributes': {}}], + ['opentag', {'name': 'R', 'attributes': {}, 'isSelfClosing': false}], + ['opencdata', undefined], + ['cdata', '12345678901'], + ['cdata', ''], + ['closecdata', undefined], + ['closetag', 'R'] + ] +}).write('') + +sax.MAX_BUFFER_LENGTH = bl