(xmlData)
| 283 | } |
| 284 | } |
| 285 | const parseXml = function (xmlData) { |
| 286 | xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line |
| 287 | const xmlObj = new xmlNode('!xml'); |
| 288 | let currentNode = xmlObj; |
| 289 | let textData = ""; |
| 290 | |
| 291 | // Reset matcher for new document |
| 292 | this.matcher.reset(); |
| 293 | this.entityDecoder.reset(); |
| 294 | |
| 295 | // Reset entity expansion counters for this document |
| 296 | this.entityExpansionCount = 0; |
| 297 | this.currentExpandedLength = 0; |
| 298 | this.doctypefound = false; |
| 299 | const options = this.options; |
| 300 | const docTypeReader = new DocTypeReader(options.processEntities); |
| 301 | const xmlLen = xmlData.length; |
| 302 | for (let i = 0; i < xmlLen; i++) {//for each char in XML data |
| 303 | const ch = xmlData[i]; |
| 304 | if (ch === '<') { |
| 305 | // const nextIndex = i+1; |
| 306 | // const _2ndChar = xmlData[nextIndex]; |
| 307 | const c1 = xmlData.charCodeAt(i + 1); |
| 308 | if (c1 === 47) {//Closing Tag '/' |
| 309 | const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.") |
| 310 | let tagName = xmlData.substring(i + 2, closeIndex).trim(); |
| 311 | |
| 312 | if (options.removeNSPrefix) { |
| 313 | const colonIndex = tagName.indexOf(":"); |
| 314 | if (colonIndex !== -1) { |
| 315 | tagName = tagName.substr(colonIndex + 1); |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | tagName = transformTagName(options.transformTagName, tagName, "", options).tagName; |
| 320 | |
| 321 | if (currentNode) { |
| 322 | textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher); |
| 323 | } |
| 324 | |
| 325 | //check if last tag of nested tag was unpaired tag |
| 326 | const lastTagName = this.matcher.getCurrentTag(); |
| 327 | if (tagName && options.unpairedTagsSet.has(tagName)) { |
| 328 | throw new Error(`Unpaired tag can not be used as closing tag: </${tagName}>`); |
| 329 | } |
| 330 | if (lastTagName && options.unpairedTagsSet.has(lastTagName)) { |
| 331 | // Pop the unpaired tag |
| 332 | this.matcher.pop(); |
| 333 | this.tagsNodeStack.pop(); |
| 334 | } |
| 335 | // Pop the closing tag |
| 336 | this.matcher.pop(); |
| 337 | this.isCurrentNodeStopNode = false; // Reset flag when closing tag |
| 338 | |
| 339 | currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope |
| 340 | textData = ""; |
| 341 | i = closeIndex; |
| 342 | } else if (c1 === 63) { //'?' |
nothing calls this directly
no test coverage detected