diff --git a/lib/sax.js b/lib/sax.js index 552c4d3..7b4b1c7 100644 --- a/lib/sax.js +++ b/lib/sax.js @@ -1376,7 +1376,15 @@ } if (c === ';') { - parser[buffer] += parseEntity(parser) + var parsedEntity = parseEntity(parser) + + // Custom entities can contain tags, so we potentially need to parse the result + if (parser.state === S.TEXT_ENTITY && !sax.ENTITIES[parser.entity] && parsedEntity !== '&' + parser.entity + ';') { + chunk = chunk.slice(0, i) + parsedEntity + chunk.slice(i) + } else { + parser[buffer] += parsedEntity + } + parser.entity = '' parser.state = returnState } else if (isMatch(parser.entity.length ? entityBody : entityStart, c)) { diff --git a/test/entity-tags.js b/test/entity-tags.js new file mode 100644 index 0000000..7f17526 --- /dev/null +++ b/test/entity-tags.js @@ -0,0 +1,15 @@ +require(__dirname).test({ + xml: 'testing &custom; hi &unknown;', + entities: { + custom: 'hi' + }, + expect: [ + ['text', 'testing '], + ['opentagstart', {'name': 'FOO', attributes: {}}], + ['attribute', {name: 'BAR', value: 'baz'}], + ['opentag', {'name': 'FOO', attributes: {BAR: 'baz'}, isSelfClosing: false}], + ['text', 'hi'], + ['closetag', 'FOO'], + ['text', ' hi &unknown;'] + ] +}) diff --git a/test/index.js b/test/index.js index 1df008f..a5335b6 100644 --- a/test/index.js +++ b/test/index.js @@ -10,6 +10,11 @@ exports.sax = sax exports.test = function test (options) { var xml = options.xml var parser = sax.parser(options.strict, options.opt) + if (options.entities) { + for (var key in options.entities) { + parser.ENTITIES[key] = options.entities[key] + } + } var expect = options.expect var e = 0 sax.EVENTS.forEach(function (ev) {