From 7307e9cd9db53f96e8f8b59e01a9dd3bb1dc2829 Mon Sep 17 00:00:00 2001 From: Arthur Albuquerque <20231694+troclaux@users.noreply.github.com> Date: Tue, 6 Oct 2026 21:45:28 -0300 Subject: [PATCH] fix: validator; accept XML name characters in entity references validateAmpersand only accepted \w characters, so a valid reference such as &foo-bar; made validate() (and parse(xml, true)) fail with InvalidChar even though the parser itself resolves it. Accept any XML NameChar instead; the 20 character limit is unchanged. --- spec/validator_spec.js | 14 ++++++++++++++ src/util.js | 5 +++++ src/validator.js | 4 ++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/spec/validator_spec.js b/spec/validator_spec.js index d1cf43bc..0c7784aa 100644 --- a/spec/validator_spec.js +++ b/spec/validator_spec.js @@ -378,6 +378,20 @@ attribute2="attribute2" validate('jekyll &abcdefghij1234567890;'); validate('jekyll &abcdefghij1234567890a;', error); // limit to 20 chars }); + + it('should validate entity names with "-", "." and other XML name characters', function () { + const error = { + InvalidChar: "char '&' is not expected." + }; + validate('jekyll &foo-bar; hyde'); + validate('jekyll &foo.bar; hyde'); + validate('jekyll &foo:bar; hyde'); + validate('jekyll &caf\u00e9; hyde'); + validate(']>&foo-bar;'); + validate('jekyll &foo bar; hyde', error); + validate('jekyll &foo+bar; hyde', error); + validate('jekyll &foo-bar hyde', error); + }); }); describe("should not validate XML documents with multiple root nodes", () => { diff --git a/src/util.js b/src/util.js index c2c809d1..ffcf30f4 100644 --- a/src/util.js +++ b/src/util.js @@ -4,6 +4,7 @@ const nameStartChar = ':A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0 const nameChar = nameStartChar + '\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040'; export const nameRegexp = '[' + nameStartChar + '][' + nameChar + ']*'; const regexName = new RegExp('^' + nameRegexp + '$'); +const regexNameChar = new RegExp('^[' + nameChar + ']$'); export function getAllMatches(string, regex) { const matches = []; @@ -26,6 +27,10 @@ export const isName = function (string) { return !(match === null || typeof match === 'undefined'); } +export const isNameChar = function (char) { + return regexNameChar.test(char); +} + export function isExist(v) { return typeof v !== 'undefined'; } diff --git a/src/validator.js b/src/validator.js index 6f9904f0..8c1e25a8 100644 --- a/src/validator.js +++ b/src/validator.js @@ -1,6 +1,6 @@ 'use strict'; -import { isName } from './util.js'; +import { isName, isNameChar } from './util.js'; const defaultOptions = { allowBooleanAttributes: false, //A tag can have attributes without any value @@ -471,7 +471,7 @@ function validateAmpersand(xmlData, i) { } let count = 0; for (; i < xmlData.length; i++, count++) { - if (xmlData[i].match(/\w/) && count < 20) + if (isNameChar(xmlData[i]) && count < 20) continue; if (xmlData[i] === ';') break;