const {XMLParser, XMLBuilder} = require("../src/fxp"); describe("XMLParser Entities", function() { it("should parse attributes with valid names, default entities", function() { const xmlData = ` 1 2 2 test&\r\nтест<\r\ntest <<b>2]]]]>\r\n&]]>a \ страхования\ » от суммы \ его активов\ `; const expected = { "a:root": { "@_xmlns:a": "urn:none", "@_xmlns:a-b": "urn:none", "a:a": { "#text": 1, "@_attr": "2foo&bar'" }, "a:b": 2, "a-b:b-a": 2, "a:c": "test&\nтест<\ntest", "a:el": "<2]]]]>&a", "c:string": { "#text": "страхования » от суммы его активов", "@_lang": "ru" } } }; const options = { allowBooleanAttributes: true, ignoreAttributes: false, }; const parser = new XMLParser(options); let result = parser.parse(xmlData, true); //console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); it("should parse XML with DOCTYPE without internal DTD", function() { const xmlData = "test"; const expected = { "?xml": { "@_version": "1.0", "@_standalone": "no" }, "svg" : { "metadata": "test" } }; const options = { allowBooleanAttributes: true, ignoreAttributes: false, }; const parser = new XMLParser(options); let result = parser.parse(xmlData, true); expect(result).toEqual(expected); }); it("should parse XML with DOCTYPE without internal DTD", function() { const xmlData = ` [test] `; const expected = { "?xml": { "@_version": "1.0", "@_standalone": "no" }, "svg" : { "metadata": "[test]" } }; const options = { allowBooleanAttributes: true, ignoreAttributes: false, }; const parser = new XMLParser(options); let result = parser.parse(xmlData, true); // console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); it("should error for when any tag is left to close", function(){ const xmlData = `{ const parser = new XMLParser(); parser.parse(xmlData); }).toThrowError("Unclosed DOCTYPE") }) it("should parse XML with DOCTYPE", function() { const xmlData = "" + "" + "" + "" + "" + "]>" + "Hello World."; const expected = { "?xml": "", foo: "Hello World." }; const options = { }; const parser = new XMLParser(options); let result = parser.parse(xmlData); //console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); it("should parse attributes having '>' in value", function() { const xmlData = ` ]> Tove Jani Reminder Don't forget me this weekend!
&writer; ©right;
`; const expected = { "?xml": { "version": "1.0", "encoding": "UTF-8" }, "note": { "to": "Tove", "from": "Jani", "heading": "Reminder", "body": { "#text": "Don't forget me this weekend!", "attr": "Writer: Donald Duck." }, "footer": "Writer: Donald Duck. Copyright: W3Schools." } }; const options = { attributeNamePrefix: "", ignoreAttributes: false, processEntities: true }; const parser = new XMLParser(options); let result = parser.parse(xmlData); // console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); it("should parse dynamic entity", function() { const xmlData = ` ]> Reminder Don't forget me this weekend!
&writer;& ©right;
`; const expected = { "?xml": { "version": "1.0", "encoding": "UTF-8" }, "note": { "heading": "Reminder", "body": { "#text": "Don't forget me this weekend!", "attr": "Writer: Donald Duck." }, "footer": "Writer: Donald Duck.Writer: Donald Duck.Copyright: W3Schools." } }; const options = { attributeNamePrefix: "", ignoreAttributes: false, processEntities: true }; const parser = new XMLParser(options); let result = parser.parse(xmlData); // console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); it("should allow !ATTLIST & !NOTATION", function() { const xmlData = ` ]> Some VRML instructions`; const expected = { "?xml": { "version": "1.0" }, "code": { "lang": 'vrml', "#text": 'Some VRML instructions' } }; const options = { attributeNamePrefix: "", ignoreAttributes: false, processEntities: true }; const parser = new XMLParser(options); let result = parser.parse(xmlData); // console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); it("should build by decoding defaul entities", function() { const jsObj = { "note": { "@heading": "Reminder > \"Alert", "body": { "#text": " 3 < 4", "attr": "Writer: Donald Duck." }, } }; const expected = ` 3 < 4 Writer: Donald Duck. `; const options = { attributeNamePrefix: "@", ignoreAttributes: false, // processEntities: true }; const builder = new XMLBuilder(options); const result = builder.build(jsObj); expect(result.replace(/\s+/g, "")).toEqual(expected.replace(/\s+/g, "")); }); it("should build by decoding defaul entities in prserve mode", function() { const jsObj = [ { "note": [ { "body": [ { "#text": "3 < 4" }, { "attr": [ { "#text": "Writer: Donald Duck." } ] } ] } ], ":@": { "@heading": "Reminder > \"Alert" } } ]; const expected = ` 3 < 4 Writer: Donald Duck. `; const options = { attributeNamePrefix: "@", ignoreAttributes: false, preserveOrder: true, // processEntities: false }; const parser = new XMLParser(options); let result = parser.parse(expected); // console.log(JSON.stringify(result,null,4)); const builder = new XMLBuilder(options); result = builder.build(jsObj); // console.log(result); expect(result.replace(/\s+/g, "")).toEqual(expected.replace(/\s+/g, "")); }); it("should parse HTML entities when htmlEntities:true", function() { const xmlData = ` ]> Reminder Don't forget me this weekend!®
&writer;& ©right;&inr;
`; const expected = { "?xml": { "version": "1.0", "encoding": "UTF-8" }, "note": { "heading": "Reminder", "body": { "#text": "Don't forget me this weekend!®", "attr": "Writer: Donald Duck." }, "footer": "Writer: Donald Duck.Writer: Donald Duck.Copyright: W3Schools.₹" } }; const options = { attributeNamePrefix: "", ignoreAttributes: false, processEntities: true, htmlEntities: true }; const parser = new XMLParser(options); let result = parser.parse(xmlData); // console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); }); describe("XMLParser External Entites", function() { it("should throw error when an entity value has '&'", function() { const parser = new XMLParser(); expect( () => { parser.addEntity("#xD", "&\r"); }).toThrowError("Entity value can't have '&'"); }); it("should throw error when an entity identifier has '&'", function() { const parser = new XMLParser(); expect( () => { parser.addEntity(" ", "\r"); }).toThrowError("An entity must be set without '&' and ';'. Eg. use '#xD' for ' '"); }); it("should throw error when an entity identifier has ';'", function() { const parser = new XMLParser(); expect( () => { parser.addEntity("#xD;", "\r"); }).toThrowError("An entity must be set without '&' and ';'. Eg. use '#xD' for ' '"); }); it("should set and parse for valid entity set externally", function() { const xmlData = `&unknown; last `; const parser = new XMLParser(); parser.addEntity("#xD", "\r\n"); let result = parser.parse(xmlData); // console.log(JSON.stringify(result,null,4)); expect(result.note).toEqual(`&unknown;\r\nlast`); }); it("External Entity can change the behaviour of default entites", function() { const xmlData = `>last `; const parser = new XMLParser(); parser.addEntity("gt", "<>"); let result = parser.parse(xmlData); // console.log(JSON.stringify(result,null,4)); expect(result.note).toEqual(`<>last`); }); it("Same external Entity can be set by multiple times", function() { const xmlData = `>last `; const parser = new XMLParser(); parser.addEntity("gt", "<>"); parser.addEntity("gt", "><"); let result = parser.parse(xmlData); // console.log(JSON.stringify(result,null,4)); expect(result.note).toEqual(`> \"Alert" } } ]; const expected = ` (3 & 4) < 5 Writer: Donald Duck. `; const options = { attributeNamePrefix: "@", ignoreAttributes: false, preserveOrder: true, // processEntities: false }; const parser = new XMLParser(options); let result = parser.parse(expected); // console.log(JSON.stringify(result,null,4)); const builder = new XMLBuilder(options); result = builder.build(jsObj); // console.log(result); expect(result.replace(/\s+/g, "")).toEqual(expected.replace(/\s+/g, "")); }); it("should build by decoding '&'", function() { const jsObj = { "note": { "body": { "attr": "Writer: Donald Duck.", "#text": "(3 & 4) < 5" }, "@heading": "Reminder > \"Alert" } }; const expected = ` Writer: Donald Duck. (3 & 4) < 5 `; const options = { attributeNamePrefix: "@", ignoreAttributes: false, }; const parser = new XMLParser(options); let result = parser.parse(expected); // console.log(JSON.stringify(result,null,4)); // expect(expected).toEqual(jsObj); const builder = new XMLBuilder(options); const output = builder.build(jsObj); // console.log(output); expect(output.replace(/\s+/g, "")).toEqual(expected.replace(/\s+/g, "")); }); it("should replace '&lt;' with '<'", function() { const xmlData = ` &lt; `; const expected = { "SimpleScalarPropertiesInputOutput": { "stringValue": "<" } }; const options = { attributeNamePrefix: "", ignoreAttributes: false, processEntities: true, // preserveOrder: true }; const parser = new XMLParser(options); let result = parser.parse(xmlData); //console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); });