diff --git a/lib/saxes.js b/lib/saxes.js index c8f9369c..3e26a859 100644 --- a/lib/saxes.js +++ b/lib/saxes.js @@ -24,14 +24,21 @@ const XML_ENTITIES = { const S_INITIAL = "sInitial"; // initial state const S_BEGIN_WHITESPACE = "sBeginWhitespace"; // leading whitespace +const S_DOCTYPE = "sDoctype"; // will be recorded as + // a comment of " blah -- bloo " + this.state = S_DTD_COMMENT; + } + } + + /** @private */ + sDTDPI() { + if (this.captureToChar(QUESTION, "doctype")) { + this.doctype += "?"; + this.state = S_DTD_PI_ENDING; + } + } + + /** @private */ + sDTDPIEnding() { + const c = this.getCode(); + this.doctype += String.fromCodePoint(c); + if (c === GREATER) { + this.state = S_DTD; + } + } + /** @private */ sComment() { if (this.captureToChar(MINUS, "comment")) { diff --git a/test/dtd.js b/test/dtd.js new file mode 100644 index 00000000..47b8533e --- /dev/null +++ b/test/dtd.js @@ -0,0 +1,65 @@ +"use strict"; + +const { test } = require("."); + +describe("dtd", () => { + test({ + name: "DTD with comment containing a quote", + xml: `\ + + +]> +`, + expect: [ + ["text", "\n"], + ["doctype", ` root [ + +]`], + ["text", "\n"], + ["opentagstart", { name: "root", attributes: {} }], + ["opentag", { name: "root", attributes: {}, isSelfClosing: true }], + ["closetag", { name: "root", attributes: {}, isSelfClosing: true }], + ], + }); + + test({ + name: "DTD with processing instruction containing a quote", + xml: `\ + + +]> +`, + expect: [ + ["text", "\n"], + ["doctype", ` root [ + +]`], + ["text", "\n"], + ["opentagstart", { name: "root", attributes: {} }], + ["opentag", { name: "root", attributes: {}, isSelfClosing: true }], + ["closetag", { name: "root", attributes: {}, isSelfClosing: true }], + ], + }); + + test({ + name: "DTD with ]> in a string", + xml: `\ + +"> +]> +`, + expect: [ + ["text", "\n"], + ["doctype", ` root [ +"> +]`], + ["text", "\n"], + ["opentagstart", { name: "root", attributes: {} }], + ["opentag", { name: "root", attributes: {}, isSelfClosing: true }], + ["closetag", { name: "root", attributes: {}, isSelfClosing: true }], + ], + }); +});