Skip to content

Commit a8ccdb9

Browse files
orgadsamitguptagwl
authored andcommitted
Validator: Fail for stray ampersand characters (#215)
* Introduce a helper function for simplifying the tests The following: const xmlData = '<name length="bar" length="baz"></name>'; var expected = { code: 'InvalidAttr', msg: "Attribute 'length' is repeated.", line: 1 } var result = validator.validate(xmlData).err; expect(result).toEqual(expected); Can be replaced by: validate('<name length="bar" length="baz"></name>', { InvalidAttr: "Attribute 'length' is repeated." } * Validator: Fail for stray ampersand characters Fixes #214
1 parent df830dc commit a8ccdb9

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

spec/validator_spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
const validator = require("../src/validator");
44

5+
function validate(xmlData, error, line = 1) {
6+
const result = validator.validate(xmlData);
7+
if (error) {
8+
const expected = {
9+
code: Object.keys(error)[0],
10+
msg: Object.values(error)[0],
11+
line
12+
};
13+
expect(result.err).toEqual(expected);
14+
} else {
15+
expect(result).toBe(true);
16+
}
17+
}
18+
519
describe("XMLParser", function () {
620
it("should validate simple xml string", function () {
721
let xmlData = "<rootNode></rootNode>";
@@ -511,6 +525,23 @@ attribute2="attribute2"
511525
var result = validator.validate(xmlData).err;
512526
expect(result).toEqual(expected);
513527
});
528+
529+
it('should validate value with ampersand', function () {
530+
const error = {
531+
InvalidChar: "char '&' is not expected."
532+
};
533+
validate('<rootNode>jekyll &amp; hyde</rootNode>');
534+
validate('<rootNode>jekyll &#123; hyde</rootNode>');
535+
validate('<rootNode>jekyll &#x1945abcdef; hyde</rootNode>');
536+
validate('<rootNode>jekyll &#x1ah; hyde</rootNode>', error);
537+
validate('<rootNode>jekyll &#1a; hyde</rootNode>', error);
538+
validate('<rootNode>jekyll &#123 hyde</rootNode>', error);
539+
validate('<rootNode>jekyll &#1abcd hyde</rootNode>', error);
540+
validate('<rootNode>jekyll & hyde</rootNode>', error);
541+
validate('<rootNode>jekyll &aa</rootNode>', error);
542+
validate('<rootNode>jekyll &abcdefghij1234567890;</rootNode>');
543+
validate('<rootNode>jekyll &abcdefghij1234567890a;</rootNode>', error); // limit to 20 chars
544+
});
514545
});
515546

516547
describe("should not validate XML documents with multiple root nodes", () => {

src/validator.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ exports.validate = function (xmlData, options) {
155155
} else {
156156
break;
157157
}
158+
} else if (xmlData[i] === '&') {
159+
const afterAmp = validateAmpersand(xmlData, i);
160+
if (afterAmp == -1)
161+
return getErrorObject('InvalidChar', `char '&' is not expected.`, getLineNumberForPosition(xmlData, i));
162+
i = afterAmp;
158163
}
159164
} //end of reading tag text value
160165
if (xmlData[i] === '<') {
@@ -332,6 +337,41 @@ function validateAttributeString(attrStr, options, regxAttrName) {
332337
return true;
333338
}
334339

340+
function validateNumberAmpersand(xmlData, i) {
341+
let re = /\d/;
342+
if (xmlData[i] === 'x') {
343+
i++;
344+
re = /[\da-fA-F]/;
345+
}
346+
for (; i < xmlData.length; i++) {
347+
if (xmlData[i] === ';')
348+
return i;
349+
if (!xmlData[i].match(re))
350+
break;
351+
}
352+
return -1;
353+
}
354+
355+
function validateAmpersand(xmlData, i) {
356+
// https://www.w3.org/TR/xml/#dt-charref
357+
i++;
358+
if (xmlData[i] === ';')
359+
return -1;
360+
if (xmlData[i] === '#') {
361+
i++;
362+
return validateNumberAmpersand(xmlData, i);
363+
}
364+
let count = 0;
365+
for (; i < xmlData.length; i++, count++) {
366+
if (xmlData[i].match(/\w/) && count < 20)
367+
continue;
368+
if (xmlData[i] === ';')
369+
break;
370+
return -1;
371+
}
372+
return i;
373+
}
374+
335375
function getErrorObject(code, message, lineNumber) {
336376
return {
337377
err: {

0 commit comments

Comments
 (0)