diff --git a/spec/cdata_spec.js b/spec/cdata_spec.js index 821179a5..b0026582 100644 --- a/spec/cdata_spec.js +++ b/spec/cdata_spec.js @@ -383,4 +383,49 @@ patronymic`; // console.log(JSON.stringify(result,null,4)); expect(result).toEqual(expected); }); + + it("should preserve carriage returns in CDATA", function () { + const xmlData = ` + + + + + + +`; + + const expected = { + "properties": { + "property": [ + { + "#value": "This is a carriage return \r...", + "@type": "string", + "@name": "x", + "@state": "changed" + }, + { + "#value": "\r", + "@type": "string", + "@name": "y", + "@state": "changed" + } + ], + "@object": "", + "@engine": "" + } + }; + + const options = { + attributeNamePrefix: "@", + ignoreAttributes: false, + parseAttributeValue: false, + parseTagValue: false, + textNodeName: "#value", + }; + + const parser = new XMLParser(options); + let result = parser.parse(xmlData); + + expect(result).toEqual(expected); + }); }); diff --git a/src/xmlparser/OrderedObjParser.js b/src/xmlparser/OrderedObjParser.js index ec8d24d4..f3ea083c 100644 --- a/src/xmlparser/OrderedObjParser.js +++ b/src/xmlparser/OrderedObjParser.js @@ -274,8 +274,55 @@ function buildAttributesMap(attrStr, jPath, tagName, force = false) { return attrs; } } +function normalizeLineEndingsOutsideCDATA(xmlData) { + if (xmlData.indexOf("\r") === -1) return xmlData; + + let normalizedXml = ""; + let segmentStart = 0; + let insideTag = false; + let quoteChar = ""; + + for (let i = 0; i < xmlData.length; i++) { + const ch = xmlData[i]; + + if (insideTag) { + if (quoteChar) { + if (ch === quoteChar) quoteChar = ""; + } else if (ch === '"' || ch === "'") { + quoteChar = ch; + } else if (ch === ">") { + insideTag = false; + } + } else if (ch === "<") { + if (xmlData.startsWith("", i + 9); + if (cdataEnd === -1) { + normalizedXml += xmlData.substring(i); + return normalizedXml; + } + + const cdataCloseIndex = cdataEnd + 3; + normalizedXml += xmlData.substring(i, cdataCloseIndex); + i = cdataCloseIndex - 1; + segmentStart = cdataCloseIndex; + } else if (xmlData.startsWith("", i + 4); + if (commentEnd === -1) break; + i = commentEnd + 2; + } else { + insideTag = true; + } + } + } + + normalizedXml += xmlData.substring(segmentStart).replace(/\r\n?/g, "\n"); + return normalizedXml; +} + const parseXml = function (xmlData) { - xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line + xmlData = normalizeLineEndingsOutsideCDATA(xmlData); const xmlObj = new xmlNode('!xml'); let currentNode = xmlObj; let textData = ""; @@ -835,4 +882,4 @@ function sanitizeName(name, options) { return options.onDangerousProperty(name); } return name; -} \ No newline at end of file +}