From 90301fbeff5a41fb55a07701dfdc2e7cf23815f3 Mon Sep 17 00:00:00 2001 From: Louis-Dominique Dubeau Date: Mon, 20 Aug 2018 09:42:05 -0400 Subject: [PATCH] feat: add the `resolvePrefix` option This is yet another option for facilitating parsing XML fragments. This option is a callback that the parser will call if it is not able to resolve a namespace prefix. --- README.md | 15 ++++++++++++--- lib/saxes.js | 19 ++++++++++++++++++- test/fragments.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c7a56d8d..fb8b088e 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ event. The XML specification does not define any method by which to parse XML fragments. However, there are usage scenarios in which it is desirable to parse -fragments. In order to allow this, saxes provides two initialization options. +fragments. In order to allow this, saxes provides three initialization options. If you pass the option `fragment: true` to the parser constructor, the parser will expect an XML fragment. It essentially starts with a parsing state @@ -187,8 +187,17 @@ right after initialization. In other words, it expects content which is acceptable inside an element. This also turns off well-formedness checks that are inappropriate when parsing a fragment. -The other option is `additionalNamespaces`, which allows you to define -additional prefix-to-URI bindings known before parsing starts. +The option `additionalNamespaces` allows you to define additional prefix-to-URI +bindings known before parsing starts. You would use this over `resolvePrefix` if +you have at the ready a series of namespaces bindings to use. + +The option `resolvePrefix` allows you to pass a function which saxes will use if +it is unable to resolve a namespace prefix by itself. You would use this over +`additionalNamespaces` in a context where getting a complete list of defined +namespaces is onerous. + +Note that you can use `additionalNamespaces` and `resolvePrefix` together if you +want. `additionalNamespaces` applies before `resolvePrefix`. ## FAQ diff --git a/lib/saxes.js b/lib/saxes.js index 5262228d..d2d38548 100644 --- a/lib/saxes.js +++ b/lib/saxes.js @@ -222,6 +222,14 @@ ${XMLNS_NAMESPACE}.`); * specified by the XML declaration. */ +/** + * @callback ResolvePrefix + * + * @param {string} prefix The prefix to check. + * + * @returns {string|undefined} The URI corresponding to the prefix, if any. + */ + /** * @typedef SaxesOptions * @@ -235,6 +243,9 @@ ${XMLNS_NAMESPACE}.`); * pairs define namespaces known before parsing the XML file. It is not legal * to pass bindings for the namespaces ``"xml"`` or ``"xmlns"``. * + * @property {ResolvePrefix} [resolvePrefix] A function that will be used if the + * parser cannot resolve a namespace prefix on its own. + * * @property {boolean} [position] Whether to track positions. Unset means * ``true``. * @@ -1569,7 +1580,13 @@ class SaxesParser { } } - return this.ns[prefix]; + uri = this.ns[prefix]; + if (uri) { + return uri; + } + + const { resolvePrefix } = this.opt; + return resolvePrefix ? resolvePrefix(prefix) : undefined; } /** diff --git a/test/fragments.js b/test/fragments.js index 8b20c2b9..743d95ae 100644 --- a/test/fragments.js +++ b/test/fragments.js @@ -185,4 +185,46 @@ describe("fragments", () => { }, }, }); + + test({ + name: "resolvePrefix", + xml: "Something 1 something", + expect: [ + ["text", "Something "], + ["opentagstart", { + name: "foo:blah", + attributes: {}, + ns: {}, + }], + ["opentag", { + name: "foo:blah", + local: "blah", + prefix: "foo", + uri: "foo-uri", + attributes: {}, + ns: {}, + isSelfClosing: false, + }], + ["text", "1"], + ["closetag", { + name: "foo:blah", + local: "blah", + prefix: "foo", + uri: "foo-uri", + attributes: {}, + ns: {}, + isSelfClosing: false, + }], + ["text", " something"], + ], + opt: { + xmlns: true, + fragment: true, + resolvePrefix(prefix) { + return { + foo: "foo-uri", + }[prefix]; + }, + }, + }); });