From 1eedbf872b6565543b0e99f554d803874be7456f Mon Sep 17 00:00:00 2001 From: Louis-Dominique Dubeau Date: Tue, 30 Jul 2019 18:25:38 -0400 Subject: [PATCH] feat: add forceXMLVersion --- README.md | 16 +++ lib/saxes.d.ts | 13 ++- lib/saxes.js | 12 ++- test/xml-declaration.js | 220 +++++++++++++++++++++++++--------------- 4 files changed, 175 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 590516d4..a55dfc1e 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,22 @@ Settings supported: declaration, then this setting is ignored. Must be `"1.0"` or `"1.1"`. The default is `"1.0"`. +* `forceXMLVersion` - Boolean. A flag indicating whether to force the XML + version used for parsing to the value of ``defaultXMLVersion``. When this flag + is ``true``, ``defaultXMLVersion`` must be specified. If unspecified, the + default value of this flag is ``false``. + + Example: suppose you are parsing a document that has an XML declaration + specifying XML version 1.1. + + If you set ``defaultXMLVersion`` to ``"1.0"`` without setting + ``forceXMLVersion`` then the XML declaration will override the value of + ``defaultXMLVersion`` and the document will be parsed according to XML 1.1. + + If you set ``defaultXMLVersion`` to ``"1.0"`` and set ``forceXMLVersion`` to + ``true``, then the XML declaration will be ignored and the document will be + parsed according to XML 1.0. + ### Methods `write` - Write bytes onto the stream. You don't have to pass the whole document diff --git a/lib/saxes.d.ts b/lib/saxes.d.ts index 48e81105..6c7e1722 100644 --- a/lib/saxes.d.ts +++ b/lib/saxes.d.ts @@ -1,7 +1,7 @@ declare namespace saxes { export const EVENTS: ReadonlyArray; - export interface SaxesOptions { + export interface CommonSaxesOptions { xmlns?: boolean; position?: boolean; fragment?: boolean; @@ -10,6 +10,17 @@ declare namespace saxes { defaultXMLVersion?: "1.0" | "1.1"; } + export interface NotForced extends CommonSaxesOptions { + forceXMLVersion?: false; + } + + export interface Forced extends CommonSaxesOptions { + defaultXMLVersion: CommonSaxesOptions["defaultXMLVersion"]; + forceXMLVersion: true; + } + + export type SaxesOptions = NotForced | Forced; + export interface XMLDecl { version?: string; encoding?: string; diff --git a/lib/saxes.js b/lib/saxes.js index 8d4b90d8..55136294 100644 --- a/lib/saxes.js +++ b/lib/saxes.js @@ -268,6 +268,11 @@ const FORBIDDEN_BRACKET_BRACKET = 2; * @property {"1.0" | "1.1"} [defaultXMLVersion] The default XML version to * use. If unspecified, and there is no XML encoding declaration, the default * version is "1.0". + * + * @property {boolean} [forceXMLVersion] A flag indicating whether to force the + * XML version used for parsing to the value of ``defaultXMLVersion``. When this + * flag is ``true``, ``defaultXMLVersion`` must be specified. If unspecified, + * the default value of this flag is ``false``. */ class SaxesParser { @@ -385,7 +390,11 @@ class SaxesParser { } let { defaultXMLVersion } = this.opt; + const { forceXMLVersion } = this.opt; if (defaultXMLVersion === undefined) { + if (forceXMLVersion) { + throw new Error("forceXMLVersion set but defaultXMLVersion is not set"); + } defaultXMLVersion = "1.0"; } this.setXMLVersion(defaultXMLVersion); @@ -1480,7 +1489,8 @@ class SaxesParser { if (!/^1\.[0-9]+$/.test(version)) { this.fail("version number must match /^1\\.[0-9]+$/."); } - else { + // When forceXMLVersion is set, the XML declaration is ignored. + else if (!this.opt.forceXMLVersion) { this.setXMLVersion(version); } break; diff --git a/test/xml-declaration.js b/test/xml-declaration.js index 3e01c6d6..67e876e3 100644 --- a/test/xml-declaration.js +++ b/test/xml-declaration.js @@ -245,107 +245,159 @@ describe("xml declaration", () => { expect(seen).to.be.true; }); - function makeTests(groupName, xmlDeclaration, document, expectedResults) { + function parse(source, options) { + const parser = new saxes.SaxesParser(options); + let error = false; + parser.onerror = () => { + error = true; + }; + parser.write(source); + parser.close(); + return error; + } + + function makeDefaultXMLVersionTests(groupName, xmlDeclaration, document, + expecteUnforcedResults, + expectedForcedResults) { describe(groupName, () => { - for (const { version, expectError } of expectedResults) { + for (const { version, expectError } of expecteUnforcedResults) { const errorLabel = expectError ? "errors" : "no errors"; const title = version === undefined ? `and without defaultXMLVersion: ${errorLabel}` : `and with defaultXMLVersion === ${version}: ${errorLabel}`; it(title, () => { - const parser = - new saxes.SaxesParser(version === undefined ? undefined : - { defaultXMLVersion: version }); - let error = false; - parser.onerror = () => { - error = true; - }; - parser.write(xmlDeclaration + document); - parser.close(); - expect(error).to.equal(expectError); + expect(parse(xmlDeclaration + document, + version === undefined ? undefined : + { defaultXMLVersion: version })).to.equal(expectError); }); } + + if (xmlDeclaration !== "") { + for (const { version, expectError } of expectedForcedResults) { + const errorLabel = expectError ? "errors" : "no errors"; + it(`and with forced xml version ${version}: ${errorLabel}`, () => { + expect(parse(xmlDeclaration + document, { + defaultXMLVersion: version, + forceXMLVersion: true, + })).to.equal(expectError); + }); + } + } }); } - describe("well-formed for 1.0, not 1.1", () => { - makeTests("without XML declaration", "", WELL_FORMED_1_0_NOT_1_1, [{ - version: undefined, - expectError: false, - }, { - version: "1.0", - expectError: false, - }, { - version: "1.1", - expectError: true, - }]); + describe("document well-formed for 1.0, not 1.1", () => { + makeDefaultXMLVersionTests("without XML declaration", "", + WELL_FORMED_1_0_NOT_1_1, [{ + version: undefined, + expectError: false, + }, { + version: "1.0", + expectError: false, + }, { + version: "1.1", + expectError: true, + }]); - makeTests("with XML 1.0 declaration", XML_1_0_DECLARATION, - WELL_FORMED_1_0_NOT_1_1, [{ - version: undefined, - expectError: false, - }, { - version: "1.0", - expectError: false, - }, { - version: "1.1", - // The XML declaration overrides defaultXMLVersion. - expectError: false, - }]); + makeDefaultXMLVersionTests("with XML 1.0 declaration", XML_1_0_DECLARATION, + WELL_FORMED_1_0_NOT_1_1, [{ + version: undefined, + expectError: false, + }, { + version: "1.0", + expectError: false, + }, { + version: "1.1", + // The XML declaration overrides + // defaultXMLVersion. + expectError: false, + }], [{ + version: "1.0", + expectError: false, + }, { + version: "1.1", + expectError: true, + }]); - makeTests("with XML 1.1 declaration", XML_1_1_DECLARATION, - WELL_FORMED_1_0_NOT_1_1, [{ - version: undefined, - // The XML declaration overrides defaultXMLVersion. - expectError: true, - }, { - version: "1.0", - // The XML declaration overrides defaultXMLVersion. - expectError: true, - }, { - version: "1.1", - expectError: true, - }]); + makeDefaultXMLVersionTests("with XML 1.1 declaration", XML_1_1_DECLARATION, + WELL_FORMED_1_0_NOT_1_1, [{ + version: undefined, + // The XML declaration overrides + // defaultXMLVersion. + expectError: true, + }, { + version: "1.0", + // The XML declaration overrides + // defaultXMLVersion. + expectError: true, + }, { + version: "1.1", + expectError: true, + }], [{ + version: "1.0", + expectError: false, + }, { + version: "1.1", + expectError: true, + }]); }); - describe("well-formed for 1.1, not 1.0", () => { - makeTests("without XML declaration", "", WELL_FORMED_1_1_NOT_1_0, [{ - version: undefined, - expectError: true, - }, { - version: "1.0", - expectError: true, - }, { - version: "1.1", - expectError: false, - }]); + describe("document well-formed for 1.1, not 1.0", () => { + makeDefaultXMLVersionTests("without XML declaration", "", + WELL_FORMED_1_1_NOT_1_0, [{ + version: undefined, + expectError: true, + }, { + version: "1.0", + expectError: true, + }, { + version: "1.1", + expectError: false, + }]); - makeTests("with XML 1.0 declaration", XML_1_0_DECLARATION, - WELL_FORMED_1_1_NOT_1_0, [{ - version: undefined, - expectError: true, - }, { - version: "1.0", - expectError: true, - }, { - version: "1.1", - // The XML declaration overrides defaultXMLVersion. - expectError: true, - }]); + makeDefaultXMLVersionTests("with XML 1.0 declaration", + XML_1_0_DECLARATION, + WELL_FORMED_1_1_NOT_1_0, [{ + version: undefined, + expectError: true, + }, { + version: "1.0", + expectError: true, + }, { + version: "1.1", + // The XML declaration overrides + // defaultXMLVersion. + expectError: true, + }], [{ + version: "1.0", + expectError: true, + }, { + version: "1.1", + expectError: false, + }]); - makeTests("with XML 1.1 declaration", XML_1_1_DECLARATION, - WELL_FORMED_1_1_NOT_1_0, [{ - version: undefined, - // The XML declaration overrides defaultXMLVersion. - expectError: false, - }, { - version: "1.0", - // The XML declaration overrides defaultXMLVersion. - expectError: false, - }, { - version: "1.1", - expectError: false, - }]); + makeDefaultXMLVersionTests("with XML 1.1 declaration", + XML_1_1_DECLARATION, + WELL_FORMED_1_1_NOT_1_0, [{ + version: undefined, + // The XML declaration overrides + // defaultXMLVersion. + expectError: false, + }, { + version: "1.0", + // The XML declaration overrides + // defaultXMLVersion. + expectError: false, + }, { + version: "1.1", + expectError: false, + }], [{ + version: "1.0", + expectError: true, + }, { + version: "1.1", + expectError: false, + }]); }); });