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;