@lucianpacurar/iso20022.js 0.2.13 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +962 -641
- package/dist/index.mjs +962 -641
- package/dist/src/parseUtils.d.ts +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,84 +1,34 @@
|
|
|
1
1
|
import Dinero from 'dinero.js';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return !(match === null || typeof match === 'undefined');
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
exports.isExist = function(v) {
|
|
36
|
-
return typeof v !== 'undefined';
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
exports.isEmptyObject = function(obj) {
|
|
40
|
-
return Object.keys(obj).length === 0;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Copy all the properties of a into b.
|
|
45
|
-
* @param {*} target
|
|
46
|
-
* @param {*} a
|
|
47
|
-
*/
|
|
48
|
-
exports.merge = function(target, a, arrayMode) {
|
|
49
|
-
if (a) {
|
|
50
|
-
const keys = Object.keys(a); // will return an array of own properties
|
|
51
|
-
const len = keys.length; //don't make it inline
|
|
52
|
-
for (let i = 0; i < len; i++) {
|
|
53
|
-
if (arrayMode === 'strict') {
|
|
54
|
-
target[keys[i]] = [ a[keys[i]] ];
|
|
55
|
-
} else {
|
|
56
|
-
target[keys[i]] = a[keys[i]];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
/* exports.merge =function (b,a){
|
|
62
|
-
return Object.assign(b,a);
|
|
63
|
-
} */
|
|
64
|
-
|
|
65
|
-
exports.getValue = function(v) {
|
|
66
|
-
if (exports.isExist(v)) {
|
|
67
|
-
return v;
|
|
68
|
-
} else {
|
|
69
|
-
return '';
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
// const fakeCall = function(a) {return a;};
|
|
74
|
-
// const fakeCallNoReturn = function() {};
|
|
75
|
-
|
|
76
|
-
exports.isName = isName;
|
|
77
|
-
exports.getAllMatches = getAllMatches;
|
|
78
|
-
exports.nameRegexp = nameRegexp;
|
|
79
|
-
} (util$3));
|
|
80
|
-
|
|
81
|
-
const util$2 = util$3;
|
|
3
|
+
const nameStartChar = ':A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
|
|
4
|
+
const nameChar = nameStartChar + '\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
|
|
5
|
+
const nameRegexp = '[' + nameStartChar + '][' + nameChar + ']*';
|
|
6
|
+
const regexName = new RegExp('^' + nameRegexp + '$');
|
|
7
|
+
|
|
8
|
+
function getAllMatches(string, regex) {
|
|
9
|
+
const matches = [];
|
|
10
|
+
let match = regex.exec(string);
|
|
11
|
+
while (match) {
|
|
12
|
+
const allmatches = [];
|
|
13
|
+
allmatches.startIndex = regex.lastIndex - match[0].length;
|
|
14
|
+
const len = match.length;
|
|
15
|
+
for (let index = 0; index < len; index++) {
|
|
16
|
+
allmatches.push(match[index]);
|
|
17
|
+
}
|
|
18
|
+
matches.push(allmatches);
|
|
19
|
+
match = regex.exec(string);
|
|
20
|
+
}
|
|
21
|
+
return matches;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isName = function (string) {
|
|
25
|
+
const match = regexName.exec(string);
|
|
26
|
+
return !(match === null || typeof match === 'undefined');
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function isExist(v) {
|
|
30
|
+
return typeof v !== 'undefined';
|
|
31
|
+
}
|
|
82
32
|
|
|
83
33
|
const defaultOptions$2 = {
|
|
84
34
|
allowBooleanAttributes: false, //A tag can have attributes without any value
|
|
@@ -86,7 +36,7 @@ const defaultOptions$2 = {
|
|
|
86
36
|
};
|
|
87
37
|
|
|
88
38
|
//const tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g");
|
|
89
|
-
|
|
39
|
+
function validate(xmlData, options) {
|
|
90
40
|
options = Object.assign({}, defaultOptions$2, options);
|
|
91
41
|
|
|
92
42
|
//xmlData = xmlData.replace(/(\r\n|\n|\r)/gm,"");//make it single line
|
|
@@ -264,8 +214,7 @@ validator$2.validate = function (xmlData, options) {
|
|
|
264
214
|
}
|
|
265
215
|
|
|
266
216
|
return true;
|
|
267
|
-
}
|
|
268
|
-
|
|
217
|
+
}
|
|
269
218
|
function isWhiteSpace(char){
|
|
270
219
|
return char === ' ' || char === '\t' || char === '\n' || char === '\r';
|
|
271
220
|
}
|
|
@@ -395,7 +344,7 @@ function validateAttributeString(attrStr, options) {
|
|
|
395
344
|
|
|
396
345
|
//if(attrStr.trim().length === 0) return true; //empty string
|
|
397
346
|
|
|
398
|
-
const matches =
|
|
347
|
+
const matches = getAllMatches(attrStr, validAttrStrRegxp);
|
|
399
348
|
const attrNames = {};
|
|
400
349
|
|
|
401
350
|
for (let i = 0; i < matches.length; i++) {
|
|
@@ -473,13 +422,13 @@ function getErrorObject(code, message, lineNumber) {
|
|
|
473
422
|
}
|
|
474
423
|
|
|
475
424
|
function validateAttrName(attrName) {
|
|
476
|
-
return
|
|
425
|
+
return isName(attrName);
|
|
477
426
|
}
|
|
478
427
|
|
|
479
428
|
// const startsWithXML = /^xml/i;
|
|
480
429
|
|
|
481
430
|
function validateTagName(tagname) {
|
|
482
|
-
return
|
|
431
|
+
return isName(tagname) /* && !tagname.match(startsWithXML) */;
|
|
483
432
|
}
|
|
484
433
|
|
|
485
434
|
//this function returns the line number for the character at the given index
|
|
@@ -498,55 +447,100 @@ function getPositionFromMatch(match) {
|
|
|
498
447
|
return match.startIndex + match[1].length;
|
|
499
448
|
}
|
|
500
449
|
|
|
501
|
-
var OptionsBuilder = {};
|
|
502
|
-
|
|
503
450
|
const defaultOptions$1 = {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
451
|
+
preserveOrder: false,
|
|
452
|
+
attributeNamePrefix: '@_',
|
|
453
|
+
attributesGroupName: false,
|
|
454
|
+
textNodeName: '#text',
|
|
455
|
+
ignoreAttributes: true,
|
|
456
|
+
removeNSPrefix: false, // remove NS from tag name or attribute name if true
|
|
457
|
+
allowBooleanAttributes: false, //a tag can have attributes without any value
|
|
458
|
+
//ignoreRootElement : false,
|
|
459
|
+
parseTagValue: true,
|
|
460
|
+
parseAttributeValue: false,
|
|
461
|
+
trimValues: true, //Trim string values of tag and attributes
|
|
462
|
+
cdataPropName: false,
|
|
463
|
+
numberParseOptions: {
|
|
464
|
+
hex: true,
|
|
465
|
+
leadingZeros: true,
|
|
466
|
+
eNotation: true
|
|
467
|
+
},
|
|
468
|
+
tagValueProcessor: function (tagName, val) {
|
|
469
|
+
return val;
|
|
470
|
+
},
|
|
471
|
+
attributeValueProcessor: function (attrName, val) {
|
|
472
|
+
return val;
|
|
473
|
+
},
|
|
474
|
+
stopNodes: [], //nested tags will not be parsed even for errors
|
|
475
|
+
alwaysCreateTextNode: false,
|
|
476
|
+
isArray: () => false,
|
|
477
|
+
commentPropName: false,
|
|
478
|
+
unpairedTags: [],
|
|
479
|
+
processEntities: true,
|
|
480
|
+
htmlEntities: false,
|
|
481
|
+
ignoreDeclaration: false,
|
|
482
|
+
ignorePiTags: false,
|
|
483
|
+
transformTagName: false,
|
|
484
|
+
transformAttributeName: false,
|
|
485
|
+
updateTag: function (tagName, jPath, attrs) {
|
|
486
|
+
return tagName
|
|
487
|
+
},
|
|
488
|
+
// skipEmptyListItem: false
|
|
489
|
+
captureMetaData: false,
|
|
542
490
|
};
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Normalizes processEntities option for backward compatibility
|
|
494
|
+
* @param {boolean|object} value
|
|
495
|
+
* @returns {object} Always returns normalized object
|
|
496
|
+
*/
|
|
497
|
+
function normalizeProcessEntities(value) {
|
|
498
|
+
// Boolean backward compatibility
|
|
499
|
+
if (typeof value === 'boolean') {
|
|
500
|
+
return {
|
|
501
|
+
enabled: value, // true or false
|
|
502
|
+
maxEntitySize: 10000,
|
|
503
|
+
maxExpansionDepth: 10,
|
|
504
|
+
maxTotalExpansions: 1000,
|
|
505
|
+
maxExpandedLength: 100000,
|
|
506
|
+
allowedTags: null,
|
|
507
|
+
tagFilter: null
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Object config - merge with defaults
|
|
512
|
+
if (typeof value === 'object' && value !== null) {
|
|
513
|
+
return {
|
|
514
|
+
enabled: value.enabled !== false, // default true if not specified
|
|
515
|
+
maxEntitySize: value.maxEntitySize ?? 10000,
|
|
516
|
+
maxExpansionDepth: value.maxExpansionDepth ?? 10,
|
|
517
|
+
maxTotalExpansions: value.maxTotalExpansions ?? 1000,
|
|
518
|
+
maxExpandedLength: value.maxExpandedLength ?? 100000,
|
|
519
|
+
allowedTags: value.allowedTags ?? null,
|
|
520
|
+
tagFilter: value.tagFilter ?? null
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Default to enabled with limits
|
|
525
|
+
return normalizeProcessEntities(true);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const buildOptions = function (options) {
|
|
529
|
+
const built = Object.assign({}, defaultOptions$1, options);
|
|
530
|
+
|
|
531
|
+
// Always normalize processEntities for backward compatibility and validation
|
|
532
|
+
built.processEntities = normalizeProcessEntities(built.processEntities);
|
|
533
|
+
//console.debug(built.processEntities)
|
|
534
|
+
return built;
|
|
546
535
|
};
|
|
547
536
|
|
|
548
|
-
|
|
549
|
-
|
|
537
|
+
let METADATA_SYMBOL$1;
|
|
538
|
+
|
|
539
|
+
if (typeof Symbol !== "function") {
|
|
540
|
+
METADATA_SYMBOL$1 = "@@xmlMetadata";
|
|
541
|
+
} else {
|
|
542
|
+
METADATA_SYMBOL$1 = Symbol("XML Node Metadata");
|
|
543
|
+
}
|
|
550
544
|
|
|
551
545
|
class XmlNode{
|
|
552
546
|
constructor(tagname) {
|
|
@@ -559,279 +553,522 @@ class XmlNode{
|
|
|
559
553
|
if(key === "__proto__") key = "#__proto__";
|
|
560
554
|
this.child.push( {[key]: val });
|
|
561
555
|
}
|
|
562
|
-
addChild(node) {
|
|
556
|
+
addChild(node, startIndex) {
|
|
563
557
|
if(node.tagname === "__proto__") node.tagname = "#__proto__";
|
|
564
558
|
if(node[":@"] && Object.keys(node[":@"]).length > 0){
|
|
565
559
|
this.child.push( { [node.tagname]: node.child, [":@"]: node[":@"] });
|
|
566
560
|
}else {
|
|
567
561
|
this.child.push( { [node.tagname]: node.child });
|
|
568
562
|
}
|
|
569
|
-
|
|
563
|
+
// if requested, add the startIndex
|
|
564
|
+
if (startIndex !== undefined) {
|
|
565
|
+
// Note: for now we just overwrite the metadata. If we had more complex metadata,
|
|
566
|
+
// we might need to do an object append here: metadata = { ...metadata, startIndex }
|
|
567
|
+
this.child[this.child.length - 1][METADATA_SYMBOL$1] = { startIndex };
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/** symbol used for metadata */
|
|
571
|
+
static getMetaDataSymbol() {
|
|
572
|
+
return METADATA_SYMBOL$1;
|
|
573
|
+
}
|
|
570
574
|
}
|
|
571
575
|
|
|
572
|
-
|
|
576
|
+
class DocTypeReader {
|
|
577
|
+
constructor(options) {
|
|
578
|
+
this.suppressValidationErr = !options;
|
|
579
|
+
this.options = options;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
readDocType(xmlData, i) {
|
|
583
|
+
|
|
584
|
+
const entities = {};
|
|
585
|
+
if (xmlData[i + 3] === 'O' &&
|
|
586
|
+
xmlData[i + 4] === 'C' &&
|
|
587
|
+
xmlData[i + 5] === 'T' &&
|
|
588
|
+
xmlData[i + 6] === 'Y' &&
|
|
589
|
+
xmlData[i + 7] === 'P' &&
|
|
590
|
+
xmlData[i + 8] === 'E') {
|
|
591
|
+
i = i + 9;
|
|
592
|
+
let angleBracketsCount = 1;
|
|
593
|
+
let hasBody = false, comment = false;
|
|
594
|
+
let exp = "";
|
|
595
|
+
for (; i < xmlData.length; i++) {
|
|
596
|
+
if (xmlData[i] === '<' && !comment) { //Determine the tag type
|
|
597
|
+
if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {
|
|
598
|
+
i += 7;
|
|
599
|
+
let entityName, val;
|
|
600
|
+
[entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr);
|
|
601
|
+
if (val.indexOf("&") === -1) { //Parameter entities are not supported
|
|
602
|
+
const escaped = entityName.replace(/[.\-+*:]/g, '\\.');
|
|
603
|
+
entities[entityName] = {
|
|
604
|
+
regx: RegExp(`&${escaped};`, "g"),
|
|
605
|
+
val: val
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) {
|
|
610
|
+
i += 8;//Not supported
|
|
611
|
+
const { index } = this.readElementExp(xmlData, i + 1);
|
|
612
|
+
i = index;
|
|
613
|
+
} else if (hasBody && hasSeq(xmlData, "!ATTLIST", i)) {
|
|
614
|
+
i += 8;//Not supported
|
|
615
|
+
// const {index} = this.readAttlistExp(xmlData,i+1);
|
|
616
|
+
// i = index;
|
|
617
|
+
} else if (hasBody && hasSeq(xmlData, "!NOTATION", i)) {
|
|
618
|
+
i += 9;//Not supported
|
|
619
|
+
const { index } = this.readNotationExp(xmlData, i + 1, this.suppressValidationErr);
|
|
620
|
+
i = index;
|
|
621
|
+
} else if (hasSeq(xmlData, "!--", i)) comment = true;
|
|
622
|
+
else throw new Error(`Invalid DOCTYPE`);
|
|
623
|
+
|
|
624
|
+
angleBracketsCount++;
|
|
625
|
+
exp = "";
|
|
626
|
+
} else if (xmlData[i] === '>') { //Read tag content
|
|
627
|
+
if (comment) {
|
|
628
|
+
if (xmlData[i - 1] === "-" && xmlData[i - 2] === "-") {
|
|
629
|
+
comment = false;
|
|
630
|
+
angleBracketsCount--;
|
|
631
|
+
}
|
|
632
|
+
} else {
|
|
633
|
+
angleBracketsCount--;
|
|
634
|
+
}
|
|
635
|
+
if (angleBracketsCount === 0) {
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
} else if (xmlData[i] === '[') {
|
|
639
|
+
hasBody = true;
|
|
640
|
+
} else {
|
|
641
|
+
exp += xmlData[i];
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (angleBracketsCount !== 0) {
|
|
645
|
+
throw new Error(`Unclosed DOCTYPE`);
|
|
646
|
+
}
|
|
647
|
+
} else {
|
|
648
|
+
throw new Error(`Invalid Tag instead of DOCTYPE`);
|
|
649
|
+
}
|
|
650
|
+
return { entities, i };
|
|
651
|
+
}
|
|
652
|
+
readEntityExp(xmlData, i) {
|
|
653
|
+
//External entities are not supported
|
|
654
|
+
// <!ENTITY ext SYSTEM "http://normal-website.com" >
|
|
573
655
|
|
|
574
|
-
|
|
656
|
+
//Parameter entities are not supported
|
|
657
|
+
// <!ENTITY entityname "&anotherElement;">
|
|
575
658
|
|
|
576
|
-
//
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
659
|
+
//Internal entities are supported
|
|
660
|
+
// <!ENTITY entityname "replacement text">
|
|
661
|
+
|
|
662
|
+
// Skip leading whitespace after <!ENTITY
|
|
663
|
+
i = skipWhitespace(xmlData, i);
|
|
664
|
+
|
|
665
|
+
// Read entity name
|
|
666
|
+
let entityName = "";
|
|
667
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i]) && xmlData[i] !== '"' && xmlData[i] !== "'") {
|
|
668
|
+
entityName += xmlData[i];
|
|
669
|
+
i++;
|
|
670
|
+
}
|
|
671
|
+
validateEntityName(entityName);
|
|
672
|
+
|
|
673
|
+
// Skip whitespace after entity name
|
|
674
|
+
i = skipWhitespace(xmlData, i);
|
|
675
|
+
|
|
676
|
+
// Check for unsupported constructs (external entities or parameter entities)
|
|
677
|
+
if (!this.suppressValidationErr) {
|
|
678
|
+
if (xmlData.substring(i, i + 6).toUpperCase() === "SYSTEM") {
|
|
679
|
+
throw new Error("External entities are not supported");
|
|
680
|
+
} else if (xmlData[i] === "%") {
|
|
681
|
+
throw new Error("Parameter entities are not supported");
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Read entity value (internal entity)
|
|
686
|
+
let entityValue = "";
|
|
687
|
+
[i, entityValue] = this.readIdentifierVal(xmlData, i, "entity");
|
|
688
|
+
|
|
689
|
+
// Validate entity size
|
|
690
|
+
if (this.options.enabled !== false &&
|
|
691
|
+
this.options.maxEntitySize &&
|
|
692
|
+
entityValue.length > this.options.maxEntitySize) {
|
|
693
|
+
throw new Error(
|
|
694
|
+
`Entity "${entityName}" size (${entityValue.length}) exceeds maximum allowed size (${this.options.maxEntitySize})`
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
i--;
|
|
699
|
+
return [entityName, entityValue, i];
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
readNotationExp(xmlData, i) {
|
|
703
|
+
// Skip leading whitespace after <!NOTATION
|
|
704
|
+
i = skipWhitespace(xmlData, i);
|
|
705
|
+
|
|
706
|
+
// Read notation name
|
|
707
|
+
let notationName = "";
|
|
708
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
709
|
+
notationName += xmlData[i];
|
|
710
|
+
i++;
|
|
711
|
+
}
|
|
712
|
+
!this.suppressValidationErr && validateEntityName(notationName);
|
|
713
|
+
|
|
714
|
+
// Skip whitespace after notation name
|
|
715
|
+
i = skipWhitespace(xmlData, i);
|
|
716
|
+
|
|
717
|
+
// Check identifier type (SYSTEM or PUBLIC)
|
|
718
|
+
const identifierType = xmlData.substring(i, i + 6).toUpperCase();
|
|
719
|
+
if (!this.suppressValidationErr && identifierType !== "SYSTEM" && identifierType !== "PUBLIC") {
|
|
720
|
+
throw new Error(`Expected SYSTEM or PUBLIC, found "${identifierType}"`);
|
|
721
|
+
}
|
|
722
|
+
i += identifierType.length;
|
|
723
|
+
|
|
724
|
+
// Skip whitespace after identifier type
|
|
725
|
+
i = skipWhitespace(xmlData, i);
|
|
726
|
+
|
|
727
|
+
// Read public identifier (if PUBLIC)
|
|
728
|
+
let publicIdentifier = null;
|
|
729
|
+
let systemIdentifier = null;
|
|
730
|
+
|
|
731
|
+
if (identifierType === "PUBLIC") {
|
|
732
|
+
[i, publicIdentifier] = this.readIdentifierVal(xmlData, i, "publicIdentifier");
|
|
733
|
+
|
|
734
|
+
// Skip whitespace after public identifier
|
|
735
|
+
i = skipWhitespace(xmlData, i);
|
|
736
|
+
|
|
737
|
+
// Optionally read system identifier
|
|
738
|
+
if (xmlData[i] === '"' || xmlData[i] === "'") {
|
|
739
|
+
[i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
|
|
740
|
+
}
|
|
741
|
+
} else if (identifierType === "SYSTEM") {
|
|
742
|
+
// Read system identifier (mandatory for SYSTEM)
|
|
743
|
+
[i, systemIdentifier] = this.readIdentifierVal(xmlData, i, "systemIdentifier");
|
|
744
|
+
|
|
745
|
+
if (!this.suppressValidationErr && !systemIdentifier) {
|
|
746
|
+
throw new Error("Missing mandatory system identifier for SYSTEM notation");
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return { notationName, publicIdentifier, systemIdentifier, index: --i };
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
readIdentifierVal(xmlData, i, type) {
|
|
754
|
+
let identifierVal = "";
|
|
755
|
+
const startChar = xmlData[i];
|
|
756
|
+
if (startChar !== '"' && startChar !== "'") {
|
|
757
|
+
throw new Error(`Expected quoted string, found "${startChar}"`);
|
|
758
|
+
}
|
|
759
|
+
i++;
|
|
760
|
+
|
|
761
|
+
while (i < xmlData.length && xmlData[i] !== startChar) {
|
|
762
|
+
identifierVal += xmlData[i];
|
|
763
|
+
i++;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (xmlData[i] !== startChar) {
|
|
767
|
+
throw new Error(`Unterminated ${type} value`);
|
|
768
|
+
}
|
|
769
|
+
i++;
|
|
770
|
+
return [i, identifierVal];
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
readElementExp(xmlData, i) {
|
|
774
|
+
// <!ELEMENT br EMPTY>
|
|
775
|
+
// <!ELEMENT div ANY>
|
|
776
|
+
// <!ELEMENT title (#PCDATA)>
|
|
777
|
+
// <!ELEMENT book (title, author+)>
|
|
778
|
+
// <!ELEMENT name (content-model)>
|
|
779
|
+
|
|
780
|
+
// Skip leading whitespace after <!ELEMENT
|
|
781
|
+
i = skipWhitespace(xmlData, i);
|
|
782
|
+
|
|
783
|
+
// Read element name
|
|
784
|
+
let elementName = "";
|
|
785
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
786
|
+
elementName += xmlData[i];
|
|
787
|
+
i++;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Validate element name
|
|
791
|
+
if (!this.suppressValidationErr && !isName(elementName)) {
|
|
792
|
+
throw new Error(`Invalid element name: "${elementName}"`);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Skip whitespace after element name
|
|
796
|
+
i = skipWhitespace(xmlData, i);
|
|
797
|
+
let contentModel = "";
|
|
798
|
+
// Expect '(' to start content model
|
|
799
|
+
if (xmlData[i] === "E" && hasSeq(xmlData, "MPTY", i)) i += 4;
|
|
800
|
+
else if (xmlData[i] === "A" && hasSeq(xmlData, "NY", i)) i += 2;
|
|
801
|
+
else if (xmlData[i] === "(") {
|
|
802
|
+
i++; // Move past '('
|
|
803
|
+
|
|
804
|
+
// Read content model
|
|
805
|
+
while (i < xmlData.length && xmlData[i] !== ")") {
|
|
806
|
+
contentModel += xmlData[i];
|
|
807
|
+
i++;
|
|
808
|
+
}
|
|
809
|
+
if (xmlData[i] !== ")") {
|
|
810
|
+
throw new Error("Unterminated content model");
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
} else if (!this.suppressValidationErr) {
|
|
814
|
+
throw new Error(`Invalid Element Expression, found "${xmlData[i]}"`);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return {
|
|
818
|
+
elementName,
|
|
819
|
+
contentModel: contentModel.trim(),
|
|
820
|
+
index: i
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
readAttlistExp(xmlData, i) {
|
|
825
|
+
// Skip leading whitespace after <!ATTLIST
|
|
826
|
+
i = skipWhitespace(xmlData, i);
|
|
827
|
+
|
|
828
|
+
// Read element name
|
|
829
|
+
let elementName = "";
|
|
830
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
831
|
+
elementName += xmlData[i];
|
|
832
|
+
i++;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Validate element name
|
|
836
|
+
validateEntityName(elementName);
|
|
837
|
+
|
|
838
|
+
// Skip whitespace after element name
|
|
839
|
+
i = skipWhitespace(xmlData, i);
|
|
840
|
+
|
|
841
|
+
// Read attribute name
|
|
842
|
+
let attributeName = "";
|
|
843
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
844
|
+
attributeName += xmlData[i];
|
|
845
|
+
i++;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// Validate attribute name
|
|
849
|
+
if (!validateEntityName(attributeName)) {
|
|
850
|
+
throw new Error(`Invalid attribute name: "${attributeName}"`);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Skip whitespace after attribute name
|
|
854
|
+
i = skipWhitespace(xmlData, i);
|
|
855
|
+
|
|
856
|
+
// Read attribute type
|
|
857
|
+
let attributeType = "";
|
|
858
|
+
if (xmlData.substring(i, i + 8).toUpperCase() === "NOTATION") {
|
|
859
|
+
attributeType = "NOTATION";
|
|
860
|
+
i += 8; // Move past "NOTATION"
|
|
861
|
+
|
|
862
|
+
// Skip whitespace after "NOTATION"
|
|
863
|
+
i = skipWhitespace(xmlData, i);
|
|
864
|
+
|
|
865
|
+
// Expect '(' to start the list of notations
|
|
866
|
+
if (xmlData[i] !== "(") {
|
|
867
|
+
throw new Error(`Expected '(', found "${xmlData[i]}"`);
|
|
868
|
+
}
|
|
869
|
+
i++; // Move past '('
|
|
870
|
+
|
|
871
|
+
// Read the list of allowed notations
|
|
872
|
+
let allowedNotations = [];
|
|
873
|
+
while (i < xmlData.length && xmlData[i] !== ")") {
|
|
874
|
+
let notation = "";
|
|
875
|
+
while (i < xmlData.length && xmlData[i] !== "|" && xmlData[i] !== ")") {
|
|
876
|
+
notation += xmlData[i];
|
|
877
|
+
i++;
|
|
601
878
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
angleBracketsCount++;
|
|
609
|
-
exp = "";
|
|
610
|
-
} else if (xmlData[i] === '>') { //Read tag content
|
|
611
|
-
if(comment){
|
|
612
|
-
if( xmlData[i - 1] === "-" && xmlData[i - 2] === "-"){
|
|
613
|
-
comment = false;
|
|
614
|
-
angleBracketsCount--;
|
|
615
|
-
}
|
|
616
|
-
}else {
|
|
617
|
-
angleBracketsCount--;
|
|
879
|
+
|
|
880
|
+
// Validate notation name
|
|
881
|
+
notation = notation.trim();
|
|
882
|
+
if (!validateEntityName(notation)) {
|
|
883
|
+
throw new Error(`Invalid notation name: "${notation}"`);
|
|
618
884
|
}
|
|
619
|
-
|
|
620
|
-
|
|
885
|
+
|
|
886
|
+
allowedNotations.push(notation);
|
|
887
|
+
|
|
888
|
+
// Skip '|' separator or exit loop
|
|
889
|
+
if (xmlData[i] === "|") {
|
|
890
|
+
i++; // Move past '|'
|
|
891
|
+
i = skipWhitespace(xmlData, i); // Skip optional whitespace after '|'
|
|
621
892
|
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (xmlData[i] !== ")") {
|
|
896
|
+
throw new Error("Unterminated list of notations");
|
|
897
|
+
}
|
|
898
|
+
i++; // Move past ')'
|
|
899
|
+
|
|
900
|
+
// Store the allowed notations as part of the attribute type
|
|
901
|
+
attributeType += " (" + allowedNotations.join("|") + ")";
|
|
902
|
+
} else {
|
|
903
|
+
// Handle simple types (e.g., CDATA, ID, IDREF, etc.)
|
|
904
|
+
while (i < xmlData.length && !/\s/.test(xmlData[i])) {
|
|
905
|
+
attributeType += xmlData[i];
|
|
906
|
+
i++;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Validate simple attribute type
|
|
910
|
+
const validTypes = ["CDATA", "ID", "IDREF", "IDREFS", "ENTITY", "ENTITIES", "NMTOKEN", "NMTOKENS"];
|
|
911
|
+
if (!this.suppressValidationErr && !validTypes.includes(attributeType.toUpperCase())) {
|
|
912
|
+
throw new Error(`Invalid attribute type: "${attributeType}"`);
|
|
626
913
|
}
|
|
627
914
|
}
|
|
628
|
-
|
|
629
|
-
|
|
915
|
+
|
|
916
|
+
// Skip whitespace after attribute type
|
|
917
|
+
i = skipWhitespace(xmlData, i);
|
|
918
|
+
|
|
919
|
+
// Read default value
|
|
920
|
+
let defaultValue = "";
|
|
921
|
+
if (xmlData.substring(i, i + 8).toUpperCase() === "#REQUIRED") {
|
|
922
|
+
defaultValue = "#REQUIRED";
|
|
923
|
+
i += 8;
|
|
924
|
+
} else if (xmlData.substring(i, i + 7).toUpperCase() === "#IMPLIED") {
|
|
925
|
+
defaultValue = "#IMPLIED";
|
|
926
|
+
i += 7;
|
|
927
|
+
} else {
|
|
928
|
+
[i, defaultValue] = this.readIdentifierVal(xmlData, i, "ATTLIST");
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
return {
|
|
932
|
+
elementName,
|
|
933
|
+
attributeName,
|
|
934
|
+
attributeType,
|
|
935
|
+
defaultValue,
|
|
936
|
+
index: i
|
|
630
937
|
}
|
|
631
|
-
}else {
|
|
632
|
-
throw new Error(`Invalid Tag instead of DOCTYPE`);
|
|
633
938
|
}
|
|
634
|
-
return {entities, i};
|
|
635
939
|
}
|
|
636
940
|
|
|
637
|
-
function readEntityExp(xmlData,i){
|
|
638
|
-
//External entities are not supported
|
|
639
|
-
// <!ENTITY ext SYSTEM "http://normal-website.com" >
|
|
640
941
|
|
|
641
|
-
//Parameter entities are not supported
|
|
642
|
-
// <!ENTITY entityname "&anotherElement;">
|
|
643
942
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
// if(xmlData[i] === " ") continue;
|
|
651
|
-
// else
|
|
652
|
-
entityName += xmlData[i];
|
|
653
|
-
}
|
|
654
|
-
entityName = entityName.trim();
|
|
655
|
-
if(entityName.indexOf(" ") !== -1) throw new Error("External entites are not supported");
|
|
656
|
-
|
|
657
|
-
//read Entity Value
|
|
658
|
-
const startChar = xmlData[i++];
|
|
659
|
-
let val = "";
|
|
660
|
-
for (; i < xmlData.length && xmlData[i] !== startChar ; i++) {
|
|
661
|
-
val += xmlData[i];
|
|
662
|
-
}
|
|
663
|
-
return [entityName, val, i];
|
|
664
|
-
}
|
|
943
|
+
const skipWhitespace = (data, index) => {
|
|
944
|
+
while (index < data.length && /\s/.test(data[index])) {
|
|
945
|
+
index++;
|
|
946
|
+
}
|
|
947
|
+
return index;
|
|
948
|
+
};
|
|
665
949
|
|
|
666
|
-
function isComment(xmlData, i){
|
|
667
|
-
if(xmlData[i+1] === '!' &&
|
|
668
|
-
xmlData[i+2] === '-' &&
|
|
669
|
-
xmlData[i+3] === '-') return true
|
|
670
|
-
return false
|
|
671
|
-
}
|
|
672
|
-
function isEntity(xmlData, i){
|
|
673
|
-
if(xmlData[i+1] === '!' &&
|
|
674
|
-
xmlData[i+2] === 'E' &&
|
|
675
|
-
xmlData[i+3] === 'N' &&
|
|
676
|
-
xmlData[i+4] === 'T' &&
|
|
677
|
-
xmlData[i+5] === 'I' &&
|
|
678
|
-
xmlData[i+6] === 'T' &&
|
|
679
|
-
xmlData[i+7] === 'Y') return true
|
|
680
|
-
return false
|
|
681
|
-
}
|
|
682
|
-
function isElement(xmlData, i){
|
|
683
|
-
if(xmlData[i+1] === '!' &&
|
|
684
|
-
xmlData[i+2] === 'E' &&
|
|
685
|
-
xmlData[i+3] === 'L' &&
|
|
686
|
-
xmlData[i+4] === 'E' &&
|
|
687
|
-
xmlData[i+5] === 'M' &&
|
|
688
|
-
xmlData[i+6] === 'E' &&
|
|
689
|
-
xmlData[i+7] === 'N' &&
|
|
690
|
-
xmlData[i+8] === 'T') return true
|
|
691
|
-
return false
|
|
692
|
-
}
|
|
693
950
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
xmlData[i+6] === 'I' &&
|
|
701
|
-
xmlData[i+7] === 'S' &&
|
|
702
|
-
xmlData[i+8] === 'T') return true
|
|
703
|
-
return false
|
|
704
|
-
}
|
|
705
|
-
function isNotation(xmlData, i){
|
|
706
|
-
if(xmlData[i+1] === '!' &&
|
|
707
|
-
xmlData[i+2] === 'N' &&
|
|
708
|
-
xmlData[i+3] === 'O' &&
|
|
709
|
-
xmlData[i+4] === 'T' &&
|
|
710
|
-
xmlData[i+5] === 'A' &&
|
|
711
|
-
xmlData[i+6] === 'T' &&
|
|
712
|
-
xmlData[i+7] === 'I' &&
|
|
713
|
-
xmlData[i+8] === 'O' &&
|
|
714
|
-
xmlData[i+9] === 'N') return true
|
|
715
|
-
return false
|
|
951
|
+
|
|
952
|
+
function hasSeq(data, seq, i) {
|
|
953
|
+
for (let j = 0; j < seq.length; j++) {
|
|
954
|
+
if (seq[j] !== data[i + j + 1]) return false;
|
|
955
|
+
}
|
|
956
|
+
return true;
|
|
716
957
|
}
|
|
717
958
|
|
|
718
|
-
function validateEntityName(name){
|
|
719
|
-
if (
|
|
720
|
-
|
|
959
|
+
function validateEntityName(name) {
|
|
960
|
+
if (isName(name))
|
|
961
|
+
return name;
|
|
721
962
|
else
|
|
722
963
|
throw new Error(`Invalid entity name ${name}`);
|
|
723
964
|
}
|
|
724
965
|
|
|
725
|
-
var DocTypeReader = readDocType$1;
|
|
726
|
-
|
|
727
966
|
const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
|
|
728
|
-
const numRegex = /^([\-\+])?(0*)(
|
|
729
|
-
// const octRegex =
|
|
967
|
+
const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
|
|
968
|
+
// const octRegex = /^0x[a-z0-9]+/;
|
|
730
969
|
// const binRegex = /0x[a-z0-9]+/;
|
|
731
970
|
|
|
732
|
-
|
|
733
|
-
//polyfill
|
|
734
|
-
if (!Number.parseInt && window.parseInt) {
|
|
735
|
-
Number.parseInt = window.parseInt;
|
|
736
|
-
}
|
|
737
|
-
if (!Number.parseFloat && window.parseFloat) {
|
|
738
|
-
Number.parseFloat = window.parseFloat;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
|
|
971
|
+
|
|
742
972
|
const consider = {
|
|
743
973
|
hex : true,
|
|
974
|
+
// oct: false,
|
|
744
975
|
leadingZeros: true,
|
|
745
976
|
decimalPoint: "\.",
|
|
746
|
-
eNotation: true
|
|
977
|
+
eNotation: true,
|
|
747
978
|
//skipLike: /regex/
|
|
748
979
|
};
|
|
749
980
|
|
|
750
|
-
function toNumber
|
|
751
|
-
// const options = Object.assign({}, consider);
|
|
752
|
-
// if(opt.leadingZeros === false){
|
|
753
|
-
// options.leadingZeros = false;
|
|
754
|
-
// }else if(opt.hex === false){
|
|
755
|
-
// options.hex = false;
|
|
756
|
-
// }
|
|
757
|
-
|
|
981
|
+
function toNumber(str, options = {}){
|
|
758
982
|
options = Object.assign({}, consider, options );
|
|
759
983
|
if(!str || typeof str !== "string" ) return str;
|
|
760
984
|
|
|
761
985
|
let trimmedStr = str.trim();
|
|
762
|
-
|
|
763
|
-
// else if(trimmedStr === "+0.0") return 0;
|
|
764
|
-
// else if(trimmedStr === "-0.0") return -0;
|
|
765
|
-
|
|
986
|
+
|
|
766
987
|
if(options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str;
|
|
988
|
+
else if(str==="0") return 0;
|
|
767
989
|
else if (options.hex && hexRegex.test(trimmedStr)) {
|
|
768
|
-
return
|
|
769
|
-
// }
|
|
990
|
+
return parse_int(trimmedStr, 16);
|
|
991
|
+
// }else if (options.oct && octRegex.test(str)) {
|
|
770
992
|
// return Number.parseInt(val, 8);
|
|
993
|
+
}else if (trimmedStr.includes('e') || trimmedStr.includes('E')) { //eNotation
|
|
994
|
+
return resolveEnotation(str,trimmedStr,options);
|
|
771
995
|
// }else if (options.parseBin && binRegex.test(str)) {
|
|
772
996
|
// return Number.parseInt(val, 2);
|
|
773
997
|
}else {
|
|
774
998
|
//separate negative sign, leading zeros, and rest number
|
|
775
999
|
const match = numRegex.exec(trimmedStr);
|
|
1000
|
+
// +00.123 => [ , '+', '00', '.123', ..
|
|
776
1001
|
if(match){
|
|
777
|
-
const sign = match[1];
|
|
1002
|
+
const sign = match[1] || "";
|
|
778
1003
|
const leadingZeros = match[2];
|
|
779
1004
|
let numTrimmedByZeros = trimZeros(match[3]); //complete num without leading zeros
|
|
1005
|
+
const decimalAdjacentToLeadingZeros = sign ? // 0., -00., 000.
|
|
1006
|
+
str[leadingZeros.length+1] === "."
|
|
1007
|
+
: str[leadingZeros.length] === ".";
|
|
1008
|
+
|
|
780
1009
|
//trim ending zeros for floating number
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1010
|
+
if(!options.leadingZeros //leading zeros are not allowed
|
|
1011
|
+
&& (leadingZeros.length > 1
|
|
1012
|
+
|| (leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros))){
|
|
1013
|
+
// 00, 00.3, +03.24, 03, 03.24
|
|
1014
|
+
return str;
|
|
1015
|
+
}
|
|
785
1016
|
else {//no leading zeros or leading zeros are allowed
|
|
786
1017
|
const num = Number(trimmedStr);
|
|
787
|
-
const
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
}else if(eNotation){ //given number has enotation
|
|
1018
|
+
const parsedStr = String(num);
|
|
1019
|
+
|
|
1020
|
+
if( num === 0) return num;
|
|
1021
|
+
if(parsedStr.search(/[eE]/) !== -1){ //given number is long and parsed to eNotation
|
|
792
1022
|
if(options.eNotation) return num;
|
|
793
1023
|
else return str;
|
|
794
1024
|
}else if(trimmedStr.indexOf(".") !== -1){ //floating number
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
// const p = numStr.indexOf(".");
|
|
800
|
-
// const givenIntPart = numStr.substr(0,p);
|
|
801
|
-
// const givenDecPart = numStr.substr(p+1);
|
|
802
|
-
if(numStr === "0" && (numTrimmedByZeros === "") ) return num; //0.0
|
|
803
|
-
else if(numStr === numTrimmedByZeros) return num; //0.456. 0.79000
|
|
804
|
-
else if( sign && numStr === "-"+numTrimmedByZeros) return num;
|
|
1025
|
+
if(parsedStr === "0") return num; //0.0
|
|
1026
|
+
else if(parsedStr === numTrimmedByZeros) return num; //0.456. 0.79000
|
|
1027
|
+
else if( parsedStr === `${sign}${numTrimmedByZeros}`) return num;
|
|
805
1028
|
else return str;
|
|
806
1029
|
}
|
|
807
1030
|
|
|
1031
|
+
let n = leadingZeros? numTrimmedByZeros : trimmedStr;
|
|
808
1032
|
if(leadingZeros){
|
|
809
|
-
//
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
//
|
|
813
|
-
|
|
814
|
-
else if(sign+numTrimmedByZeros === numStr) return num;
|
|
815
|
-
else return str;
|
|
1033
|
+
// -009 => -9
|
|
1034
|
+
return (n === parsedStr) || (sign+n === parsedStr) ? num : str
|
|
1035
|
+
}else {
|
|
1036
|
+
// +9
|
|
1037
|
+
return (n === parsedStr) || (n === sign+parsedStr) ? num : str
|
|
816
1038
|
}
|
|
817
|
-
|
|
818
|
-
if(trimmedStr === numStr) return num;
|
|
819
|
-
else if(trimmedStr === sign+numStr) return num;
|
|
820
|
-
// else{
|
|
821
|
-
// //number with +/- sign
|
|
822
|
-
// trimmedStr.test(/[-+][0-9]);
|
|
823
|
-
|
|
824
|
-
// }
|
|
825
|
-
return str;
|
|
826
1039
|
}
|
|
827
|
-
// else if(!eNotation && trimmedStr && trimmedStr !== Number(trimmedStr) ) return str;
|
|
828
|
-
|
|
829
1040
|
}else { //non-numeric string
|
|
830
1041
|
return str;
|
|
831
1042
|
}
|
|
832
1043
|
}
|
|
833
1044
|
}
|
|
834
1045
|
|
|
1046
|
+
const eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;
|
|
1047
|
+
function resolveEnotation(str,trimmedStr,options){
|
|
1048
|
+
if(!options.eNotation) return str;
|
|
1049
|
+
const notation = trimmedStr.match(eNotationRegx);
|
|
1050
|
+
if(notation){
|
|
1051
|
+
let sign = notation[1] || "";
|
|
1052
|
+
const eChar = notation[3].indexOf("e") === -1 ? "E" : "e";
|
|
1053
|
+
const leadingZeros = notation[2];
|
|
1054
|
+
const eAdjacentToLeadingZeros = sign ? // 0E.
|
|
1055
|
+
str[leadingZeros.length+1] === eChar
|
|
1056
|
+
: str[leadingZeros.length] === eChar;
|
|
1057
|
+
|
|
1058
|
+
if(leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str;
|
|
1059
|
+
else if(leadingZeros.length === 1
|
|
1060
|
+
&& (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)){
|
|
1061
|
+
return Number(trimmedStr);
|
|
1062
|
+
}else if(options.leadingZeros && !eAdjacentToLeadingZeros){ //accept with leading zeros
|
|
1063
|
+
//remove leading 0s
|
|
1064
|
+
trimmedStr = (notation[1] || "") + notation[3];
|
|
1065
|
+
return Number(trimmedStr);
|
|
1066
|
+
}else return str;
|
|
1067
|
+
}else {
|
|
1068
|
+
return str;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
835
1072
|
/**
|
|
836
1073
|
*
|
|
837
1074
|
* @param {string} numStr without leading zeros
|
|
@@ -842,14 +1079,21 @@ function trimZeros(numStr){
|
|
|
842
1079
|
numStr = numStr.replace(/0+$/, ""); //remove ending zeros
|
|
843
1080
|
if(numStr === ".") numStr = "0";
|
|
844
1081
|
else if(numStr[0] === ".") numStr = "0"+numStr;
|
|
845
|
-
else if(numStr[numStr.length-1] === ".") numStr = numStr.
|
|
1082
|
+
else if(numStr[numStr.length-1] === ".") numStr = numStr.substring(0,numStr.length-1);
|
|
846
1083
|
return numStr;
|
|
847
1084
|
}
|
|
848
1085
|
return numStr;
|
|
849
1086
|
}
|
|
850
|
-
var strnum = toNumber$1;
|
|
851
1087
|
|
|
852
|
-
function
|
|
1088
|
+
function parse_int(numStr, base){
|
|
1089
|
+
//polyfill
|
|
1090
|
+
if(parseInt) return parseInt(numStr, base);
|
|
1091
|
+
else if(Number.parseInt) return Number.parseInt(numStr, base);
|
|
1092
|
+
else if(window && window.parseInt) return window.parseInt(numStr, base);
|
|
1093
|
+
else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function getIgnoreAttributesFn(ignoreAttributes) {
|
|
853
1097
|
if (typeof ignoreAttributes === 'function') {
|
|
854
1098
|
return ignoreAttributes
|
|
855
1099
|
}
|
|
@@ -868,16 +1112,6 @@ function getIgnoreAttributesFn$2(ignoreAttributes) {
|
|
|
868
1112
|
return () => false
|
|
869
1113
|
}
|
|
870
1114
|
|
|
871
|
-
var ignoreAttributes = getIgnoreAttributesFn$2;
|
|
872
|
-
|
|
873
|
-
///@ts-check
|
|
874
|
-
|
|
875
|
-
const util = util$3;
|
|
876
|
-
const xmlNode = xmlNode$1;
|
|
877
|
-
const readDocType = DocTypeReader;
|
|
878
|
-
const toNumber = strnum;
|
|
879
|
-
const getIgnoreAttributesFn$1 = ignoreAttributes;
|
|
880
|
-
|
|
881
1115
|
// const regx =
|
|
882
1116
|
// '<((!\\[CDATA\\[([\\s\\S]*?)(]]>))|((NAME:)?(NAME))([^>]*)>|((\\/)(NAME)\\s*>))([^<]*)'
|
|
883
1117
|
// .replace(/NAME/g, util.nameRegexp);
|
|
@@ -885,19 +1119,19 @@ const getIgnoreAttributesFn$1 = ignoreAttributes;
|
|
|
885
1119
|
//const tagsRegx = new RegExp("<(\\/?[\\w:\\-\._]+)([^>]*)>(\\s*"+cdataRegx+")*([^<]+)?","g");
|
|
886
1120
|
//const tagsRegx = new RegExp("<(\\/?)((\\w*:)?([\\w:\\-\._]+))([^>]*)>([^<]*)("+cdataRegx+"([^<]*))*([^<]+)?","g");
|
|
887
1121
|
|
|
888
|
-
|
|
889
|
-
constructor(options){
|
|
1122
|
+
class OrderedObjParser {
|
|
1123
|
+
constructor(options) {
|
|
890
1124
|
this.options = options;
|
|
891
1125
|
this.currentNode = null;
|
|
892
1126
|
this.tagsNodeStack = [];
|
|
893
1127
|
this.docTypeEntities = {};
|
|
894
1128
|
this.lastEntities = {
|
|
895
|
-
"apos"
|
|
896
|
-
"gt"
|
|
897
|
-
"lt"
|
|
898
|
-
"quot"
|
|
1129
|
+
"apos": { regex: /&(apos|#39|#x27);/g, val: "'" },
|
|
1130
|
+
"gt": { regex: /&(gt|#62|#x3E);/g, val: ">" },
|
|
1131
|
+
"lt": { regex: /&(lt|#60|#x3C);/g, val: "<" },
|
|
1132
|
+
"quot": { regex: /&(quot|#34|#x22);/g, val: "\"" },
|
|
899
1133
|
};
|
|
900
|
-
this.ampEntity = { regex: /&(amp|#38|#x26);/g, val
|
|
1134
|
+
this.ampEntity = { regex: /&(amp|#38|#x26);/g, val: "&" };
|
|
901
1135
|
this.htmlEntities = {
|
|
902
1136
|
"space": { regex: /&(nbsp|#160);/g, val: " " },
|
|
903
1137
|
// "lt" : { regex: /&(lt|#60);/g, val: "<" },
|
|
@@ -905,15 +1139,15 @@ let OrderedObjParser$1 = class OrderedObjParser{
|
|
|
905
1139
|
// "amp" : { regex: /&(amp|#38);/g, val: "&" },
|
|
906
1140
|
// "quot" : { regex: /&(quot|#34);/g, val: "\"" },
|
|
907
1141
|
// "apos" : { regex: /&(apos|#39);/g, val: "'" },
|
|
908
|
-
"cent"
|
|
909
|
-
"pound"
|
|
910
|
-
"yen"
|
|
911
|
-
"euro"
|
|
912
|
-
"copyright"
|
|
913
|
-
"reg"
|
|
914
|
-
"inr"
|
|
915
|
-
"num_dec": { regex: /&#([0-9]{1,7});/g, val
|
|
916
|
-
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val
|
|
1142
|
+
"cent": { regex: /&(cent|#162);/g, val: "¢" },
|
|
1143
|
+
"pound": { regex: /&(pound|#163);/g, val: "£" },
|
|
1144
|
+
"yen": { regex: /&(yen|#165);/g, val: "¥" },
|
|
1145
|
+
"euro": { regex: /&(euro|#8364);/g, val: "€" },
|
|
1146
|
+
"copyright": { regex: /&(copy|#169);/g, val: "©" },
|
|
1147
|
+
"reg": { regex: /&(reg|#174);/g, val: "®" },
|
|
1148
|
+
"inr": { regex: /&(inr|#8377);/g, val: "₹" },
|
|
1149
|
+
"num_dec": { regex: /&#([0-9]{1,7});/g, val: (_, str) => fromCodePoint(str, 10, "&#") },
|
|
1150
|
+
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val: (_, str) => fromCodePoint(str, 16, "&#x") },
|
|
917
1151
|
};
|
|
918
1152
|
this.addExternalEntities = addExternalEntities;
|
|
919
1153
|
this.parseXml = parseXml;
|
|
@@ -925,18 +1159,35 @@ let OrderedObjParser$1 = class OrderedObjParser{
|
|
|
925
1159
|
this.readStopNodeData = readStopNodeData;
|
|
926
1160
|
this.saveTextToParentTag = saveTextToParentTag;
|
|
927
1161
|
this.addChild = addChild;
|
|
928
|
-
this.ignoreAttributesFn = getIgnoreAttributesFn
|
|
1162
|
+
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes);
|
|
1163
|
+
this.entityExpansionCount = 0;
|
|
1164
|
+
this.currentExpandedLength = 0;
|
|
1165
|
+
|
|
1166
|
+
if (this.options.stopNodes && this.options.stopNodes.length > 0) {
|
|
1167
|
+
this.stopNodesExact = new Set();
|
|
1168
|
+
this.stopNodesWildcard = new Set();
|
|
1169
|
+
for (let i = 0; i < this.options.stopNodes.length; i++) {
|
|
1170
|
+
const stopNodeExp = this.options.stopNodes[i];
|
|
1171
|
+
if (typeof stopNodeExp !== 'string') continue;
|
|
1172
|
+
if (stopNodeExp.startsWith("*.")) {
|
|
1173
|
+
this.stopNodesWildcard.add(stopNodeExp.substring(2));
|
|
1174
|
+
} else {
|
|
1175
|
+
this.stopNodesExact.add(stopNodeExp);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
929
1179
|
}
|
|
930
1180
|
|
|
931
|
-
}
|
|
1181
|
+
}
|
|
932
1182
|
|
|
933
|
-
function addExternalEntities(externalEntities){
|
|
1183
|
+
function addExternalEntities(externalEntities) {
|
|
934
1184
|
const entKeys = Object.keys(externalEntities);
|
|
935
1185
|
for (let i = 0; i < entKeys.length; i++) {
|
|
936
1186
|
const ent = entKeys[i];
|
|
1187
|
+
const escaped = ent.replace(/[.\-+*:]/g, '\\.');
|
|
937
1188
|
this.lastEntities[ent] = {
|
|
938
|
-
|
|
939
|
-
|
|
1189
|
+
regex: new RegExp("&" + escaped + ";", "g"),
|
|
1190
|
+
val: externalEntities[ent]
|
|
940
1191
|
};
|
|
941
1192
|
}
|
|
942
1193
|
}
|
|
@@ -955,23 +1206,23 @@ function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode,
|
|
|
955
1206
|
if (this.options.trimValues && !dontTrim) {
|
|
956
1207
|
val = val.trim();
|
|
957
1208
|
}
|
|
958
|
-
if(val.length > 0){
|
|
959
|
-
if(!escapeEntities) val = this.replaceEntitiesValue(val);
|
|
960
|
-
|
|
1209
|
+
if (val.length > 0) {
|
|
1210
|
+
if (!escapeEntities) val = this.replaceEntitiesValue(val, tagName, jPath);
|
|
1211
|
+
|
|
961
1212
|
const newval = this.options.tagValueProcessor(tagName, val, jPath, hasAttributes, isLeafNode);
|
|
962
|
-
if(newval === null || newval === undefined){
|
|
1213
|
+
if (newval === null || newval === undefined) {
|
|
963
1214
|
//don't parse
|
|
964
1215
|
return val;
|
|
965
|
-
}else if(typeof newval !== typeof val || newval !== val){
|
|
1216
|
+
} else if (typeof newval !== typeof val || newval !== val) {
|
|
966
1217
|
//overwrite
|
|
967
1218
|
return newval;
|
|
968
|
-
}else if(this.options.trimValues){
|
|
1219
|
+
} else if (this.options.trimValues) {
|
|
969
1220
|
return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
|
|
970
|
-
}else {
|
|
1221
|
+
} else {
|
|
971
1222
|
const trimmedVal = val.trim();
|
|
972
|
-
if(trimmedVal === val){
|
|
1223
|
+
if (trimmedVal === val) {
|
|
973
1224
|
return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
|
|
974
|
-
}else {
|
|
1225
|
+
} else {
|
|
975
1226
|
return val;
|
|
976
1227
|
}
|
|
977
1228
|
}
|
|
@@ -1002,7 +1253,7 @@ function buildAttributesMap(attrStr, jPath, tagName) {
|
|
|
1002
1253
|
// attrStr = attrStr.replace(/\r?\n/g, ' ');
|
|
1003
1254
|
//attrStr = attrStr || attrStr.trim();
|
|
1004
1255
|
|
|
1005
|
-
const matches =
|
|
1256
|
+
const matches = getAllMatches(attrStr, attrsRegx);
|
|
1006
1257
|
const len = matches.length; //don't make it inline
|
|
1007
1258
|
const attrs = {};
|
|
1008
1259
|
for (let i = 0; i < len; i++) {
|
|
@@ -1016,20 +1267,20 @@ function buildAttributesMap(attrStr, jPath, tagName) {
|
|
|
1016
1267
|
if (this.options.transformAttributeName) {
|
|
1017
1268
|
aName = this.options.transformAttributeName(aName);
|
|
1018
1269
|
}
|
|
1019
|
-
if(aName === "__proto__") aName
|
|
1270
|
+
if (aName === "__proto__") aName = "#__proto__";
|
|
1020
1271
|
if (oldVal !== undefined) {
|
|
1021
1272
|
if (this.options.trimValues) {
|
|
1022
1273
|
oldVal = oldVal.trim();
|
|
1023
1274
|
}
|
|
1024
|
-
oldVal = this.replaceEntitiesValue(oldVal);
|
|
1275
|
+
oldVal = this.replaceEntitiesValue(oldVal, tagName, jPath);
|
|
1025
1276
|
const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPath);
|
|
1026
|
-
if(newVal === null || newVal === undefined){
|
|
1277
|
+
if (newVal === null || newVal === undefined) {
|
|
1027
1278
|
//don't parse
|
|
1028
1279
|
attrs[aName] = oldVal;
|
|
1029
|
-
}else if(typeof newVal !== typeof oldVal || newVal !== oldVal){
|
|
1280
|
+
} else if (typeof newVal !== typeof oldVal || newVal !== oldVal) {
|
|
1030
1281
|
//overwrite
|
|
1031
1282
|
attrs[aName] = newVal;
|
|
1032
|
-
}else {
|
|
1283
|
+
} else {
|
|
1033
1284
|
//parse
|
|
1034
1285
|
attrs[aName] = parseValue(
|
|
1035
1286
|
oldVal,
|
|
@@ -1054,46 +1305,52 @@ function buildAttributesMap(attrStr, jPath, tagName) {
|
|
|
1054
1305
|
}
|
|
1055
1306
|
}
|
|
1056
1307
|
|
|
1057
|
-
const parseXml = function(xmlData) {
|
|
1308
|
+
const parseXml = function (xmlData) {
|
|
1058
1309
|
xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line
|
|
1059
|
-
const xmlObj = new
|
|
1310
|
+
const xmlObj = new XmlNode('!xml');
|
|
1060
1311
|
let currentNode = xmlObj;
|
|
1061
1312
|
let textData = "";
|
|
1062
1313
|
let jPath = "";
|
|
1063
|
-
|
|
1314
|
+
|
|
1315
|
+
// Reset entity expansion counters for this document
|
|
1316
|
+
this.entityExpansionCount = 0;
|
|
1317
|
+
this.currentExpandedLength = 0;
|
|
1318
|
+
|
|
1319
|
+
const docTypeReader = new DocTypeReader(this.options.processEntities);
|
|
1320
|
+
for (let i = 0; i < xmlData.length; i++) {//for each char in XML data
|
|
1064
1321
|
const ch = xmlData[i];
|
|
1065
|
-
if(ch === '<'){
|
|
1322
|
+
if (ch === '<') {
|
|
1066
1323
|
// const nextIndex = i+1;
|
|
1067
1324
|
// const _2ndChar = xmlData[nextIndex];
|
|
1068
|
-
if(
|
|
1325
|
+
if (xmlData[i + 1] === '/') {//Closing Tag
|
|
1069
1326
|
const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.");
|
|
1070
|
-
let tagName = xmlData.substring(i+2,closeIndex).trim();
|
|
1327
|
+
let tagName = xmlData.substring(i + 2, closeIndex).trim();
|
|
1071
1328
|
|
|
1072
|
-
if(this.options.removeNSPrefix){
|
|
1329
|
+
if (this.options.removeNSPrefix) {
|
|
1073
1330
|
const colonIndex = tagName.indexOf(":");
|
|
1074
|
-
if(colonIndex !== -1){
|
|
1075
|
-
tagName = tagName.substr(colonIndex+1);
|
|
1331
|
+
if (colonIndex !== -1) {
|
|
1332
|
+
tagName = tagName.substr(colonIndex + 1);
|
|
1076
1333
|
}
|
|
1077
1334
|
}
|
|
1078
1335
|
|
|
1079
|
-
if(this.options.transformTagName) {
|
|
1336
|
+
if (this.options.transformTagName) {
|
|
1080
1337
|
tagName = this.options.transformTagName(tagName);
|
|
1081
1338
|
}
|
|
1082
1339
|
|
|
1083
|
-
if(currentNode){
|
|
1340
|
+
if (currentNode) {
|
|
1084
1341
|
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1085
1342
|
}
|
|
1086
1343
|
|
|
1087
1344
|
//check if last tag of nested tag was unpaired tag
|
|
1088
|
-
const lastTagName = jPath.substring(jPath.lastIndexOf(".")+1);
|
|
1089
|
-
if(tagName && this.options.unpairedTags.indexOf(tagName) !== -1
|
|
1345
|
+
const lastTagName = jPath.substring(jPath.lastIndexOf(".") + 1);
|
|
1346
|
+
if (tagName && this.options.unpairedTags.indexOf(tagName) !== -1) {
|
|
1090
1347
|
throw new Error(`Unpaired tag can not be used as closing tag: </${tagName}>`);
|
|
1091
1348
|
}
|
|
1092
1349
|
let propIndex = 0;
|
|
1093
|
-
if(lastTagName && this.options.unpairedTags.indexOf(lastTagName) !== -1
|
|
1094
|
-
propIndex = jPath.lastIndexOf('.', jPath.lastIndexOf('.')-1);
|
|
1350
|
+
if (lastTagName && this.options.unpairedTags.indexOf(lastTagName) !== -1) {
|
|
1351
|
+
propIndex = jPath.lastIndexOf('.', jPath.lastIndexOf('.') - 1);
|
|
1095
1352
|
this.tagsNodeStack.pop();
|
|
1096
|
-
}else {
|
|
1353
|
+
} else {
|
|
1097
1354
|
propIndex = jPath.lastIndexOf(".");
|
|
1098
1355
|
}
|
|
1099
1356
|
jPath = jPath.substring(0, propIndex);
|
|
@@ -1101,72 +1358,76 @@ const parseXml = function(xmlData) {
|
|
|
1101
1358
|
currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope
|
|
1102
1359
|
textData = "";
|
|
1103
1360
|
i = closeIndex;
|
|
1104
|
-
} else if(
|
|
1361
|
+
} else if (xmlData[i + 1] === '?') {
|
|
1105
1362
|
|
|
1106
|
-
let tagData = readTagExp(xmlData,i, false, "?>");
|
|
1107
|
-
if(!tagData) throw new Error("Pi Tag is not closed.");
|
|
1363
|
+
let tagData = readTagExp(xmlData, i, false, "?>");
|
|
1364
|
+
if (!tagData) throw new Error("Pi Tag is not closed.");
|
|
1108
1365
|
|
|
1109
1366
|
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1110
|
-
if
|
|
1111
|
-
|
|
1112
|
-
const childNode = new
|
|
1367
|
+
if ((this.options.ignoreDeclaration && tagData.tagName === "?xml") || this.options.ignorePiTags) ; else {
|
|
1368
|
+
|
|
1369
|
+
const childNode = new XmlNode(tagData.tagName);
|
|
1113
1370
|
childNode.add(this.options.textNodeName, "");
|
|
1114
|
-
|
|
1115
|
-
if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
|
|
1371
|
+
|
|
1372
|
+
if (tagData.tagName !== tagData.tagExp && tagData.attrExpPresent) {
|
|
1116
1373
|
childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath, tagData.tagName);
|
|
1117
1374
|
}
|
|
1118
|
-
this.addChild(currentNode, childNode, jPath);
|
|
1119
|
-
|
|
1375
|
+
this.addChild(currentNode, childNode, jPath, i);
|
|
1120
1376
|
}
|
|
1121
1377
|
|
|
1122
1378
|
|
|
1123
1379
|
i = tagData.closeIndex + 1;
|
|
1124
|
-
} else if(xmlData.substr(i + 1, 3) === '!--') {
|
|
1125
|
-
const endIndex = findClosingIndex(xmlData, "-->", i+4, "Comment is not closed.");
|
|
1126
|
-
if(this.options.commentPropName){
|
|
1380
|
+
} else if (xmlData.substr(i + 1, 3) === '!--') {
|
|
1381
|
+
const endIndex = findClosingIndex(xmlData, "-->", i + 4, "Comment is not closed.");
|
|
1382
|
+
if (this.options.commentPropName) {
|
|
1127
1383
|
const comment = xmlData.substring(i + 4, endIndex - 2);
|
|
1128
1384
|
|
|
1129
1385
|
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1130
1386
|
|
|
1131
|
-
currentNode.add(this.options.commentPropName, [
|
|
1387
|
+
currentNode.add(this.options.commentPropName, [{ [this.options.textNodeName]: comment }]);
|
|
1132
1388
|
}
|
|
1133
1389
|
i = endIndex;
|
|
1134
|
-
} else if(
|
|
1135
|
-
const result = readDocType(xmlData, i);
|
|
1390
|
+
} else if (xmlData.substr(i + 1, 2) === '!D') {
|
|
1391
|
+
const result = docTypeReader.readDocType(xmlData, i);
|
|
1136
1392
|
this.docTypeEntities = result.entities;
|
|
1137
1393
|
i = result.i;
|
|
1138
|
-
}else if(xmlData.substr(i + 1, 2) === '![') {
|
|
1394
|
+
} else if (xmlData.substr(i + 1, 2) === '![') {
|
|
1139
1395
|
const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2;
|
|
1140
|
-
const tagExp = xmlData.substring(i + 9,closeIndex);
|
|
1396
|
+
const tagExp = xmlData.substring(i + 9, closeIndex);
|
|
1141
1397
|
|
|
1142
1398
|
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
1143
1399
|
|
|
1144
1400
|
let val = this.parseTextData(tagExp, currentNode.tagname, jPath, true, false, true, true);
|
|
1145
|
-
if(val == undefined) val = "";
|
|
1401
|
+
if (val == undefined) val = "";
|
|
1146
1402
|
|
|
1147
1403
|
//cdata should be set even if it is 0 length string
|
|
1148
|
-
if(this.options.cdataPropName){
|
|
1149
|
-
currentNode.add(this.options.cdataPropName, [
|
|
1150
|
-
}else {
|
|
1404
|
+
if (this.options.cdataPropName) {
|
|
1405
|
+
currentNode.add(this.options.cdataPropName, [{ [this.options.textNodeName]: tagExp }]);
|
|
1406
|
+
} else {
|
|
1151
1407
|
currentNode.add(this.options.textNodeName, val);
|
|
1152
1408
|
}
|
|
1153
|
-
|
|
1409
|
+
|
|
1154
1410
|
i = closeIndex + 2;
|
|
1155
|
-
}else {//Opening tag
|
|
1156
|
-
let result = readTagExp(xmlData,i, this.options.removeNSPrefix);
|
|
1157
|
-
let tagName= result.tagName;
|
|
1411
|
+
} else {//Opening tag
|
|
1412
|
+
let result = readTagExp(xmlData, i, this.options.removeNSPrefix);
|
|
1413
|
+
let tagName = result.tagName;
|
|
1158
1414
|
const rawTagName = result.rawTagName;
|
|
1159
1415
|
let tagExp = result.tagExp;
|
|
1160
1416
|
let attrExpPresent = result.attrExpPresent;
|
|
1161
1417
|
let closeIndex = result.closeIndex;
|
|
1162
1418
|
|
|
1163
1419
|
if (this.options.transformTagName) {
|
|
1164
|
-
|
|
1420
|
+
//console.log(tagExp, tagName)
|
|
1421
|
+
const newTagName = this.options.transformTagName(tagName);
|
|
1422
|
+
if (tagExp === tagName) {
|
|
1423
|
+
tagExp = newTagName;
|
|
1424
|
+
}
|
|
1425
|
+
tagName = newTagName;
|
|
1165
1426
|
}
|
|
1166
|
-
|
|
1427
|
+
|
|
1167
1428
|
//save text as child node
|
|
1168
1429
|
if (currentNode && textData) {
|
|
1169
|
-
if(currentNode.tagname !== '!xml'){
|
|
1430
|
+
if (currentNode.tagname !== '!xml') {
|
|
1170
1431
|
//when nested tag is found
|
|
1171
1432
|
textData = this.saveTextToParentTag(textData, currentNode, jPath, false);
|
|
1172
1433
|
}
|
|
@@ -1174,131 +1435,200 @@ const parseXml = function(xmlData) {
|
|
|
1174
1435
|
|
|
1175
1436
|
//check if last tag was unpaired tag
|
|
1176
1437
|
const lastTag = currentNode;
|
|
1177
|
-
if(lastTag && this.options.unpairedTags.indexOf(lastTag.tagname) !== -1
|
|
1438
|
+
if (lastTag && this.options.unpairedTags.indexOf(lastTag.tagname) !== -1) {
|
|
1178
1439
|
currentNode = this.tagsNodeStack.pop();
|
|
1179
1440
|
jPath = jPath.substring(0, jPath.lastIndexOf("."));
|
|
1180
1441
|
}
|
|
1181
|
-
if(tagName !== xmlObj.tagname){
|
|
1442
|
+
if (tagName !== xmlObj.tagname) {
|
|
1182
1443
|
jPath += jPath ? "." + tagName : tagName;
|
|
1183
1444
|
}
|
|
1184
|
-
|
|
1445
|
+
const startIndex = i;
|
|
1446
|
+
if (this.isItStopNode(this.stopNodesExact, this.stopNodesWildcard, jPath, tagName)) {
|
|
1185
1447
|
let tagContent = "";
|
|
1186
1448
|
//self-closing tag
|
|
1187
|
-
if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
|
|
1188
|
-
if(tagName[tagName.length - 1] === "/"){ //remove trailing '/'
|
|
1449
|
+
if (tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1) {
|
|
1450
|
+
if (tagName[tagName.length - 1] === "/") { //remove trailing '/'
|
|
1189
1451
|
tagName = tagName.substr(0, tagName.length - 1);
|
|
1190
1452
|
jPath = jPath.substr(0, jPath.length - 1);
|
|
1191
1453
|
tagExp = tagName;
|
|
1192
|
-
}else {
|
|
1454
|
+
} else {
|
|
1193
1455
|
tagExp = tagExp.substr(0, tagExp.length - 1);
|
|
1194
1456
|
}
|
|
1195
1457
|
i = result.closeIndex;
|
|
1196
1458
|
}
|
|
1197
1459
|
//unpaired tag
|
|
1198
|
-
else if(this.options.unpairedTags.indexOf(tagName) !== -1){
|
|
1199
|
-
|
|
1460
|
+
else if (this.options.unpairedTags.indexOf(tagName) !== -1) {
|
|
1461
|
+
|
|
1200
1462
|
i = result.closeIndex;
|
|
1201
1463
|
}
|
|
1202
1464
|
//normal tag
|
|
1203
1465
|
else {
|
|
1204
1466
|
//read until closing tag is found
|
|
1205
1467
|
const result = this.readStopNodeData(xmlData, rawTagName, closeIndex + 1);
|
|
1206
|
-
if(!result) throw new Error(`Unexpected end of ${rawTagName}`);
|
|
1468
|
+
if (!result) throw new Error(`Unexpected end of ${rawTagName}`);
|
|
1207
1469
|
i = result.i;
|
|
1208
1470
|
tagContent = result.tagContent;
|
|
1209
1471
|
}
|
|
1210
1472
|
|
|
1211
|
-
const childNode = new
|
|
1212
|
-
|
|
1473
|
+
const childNode = new XmlNode(tagName);
|
|
1474
|
+
|
|
1475
|
+
if (tagName !== tagExp && attrExpPresent) {
|
|
1213
1476
|
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
|
|
1214
1477
|
}
|
|
1215
|
-
if(tagContent) {
|
|
1478
|
+
if (tagContent) {
|
|
1216
1479
|
tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true);
|
|
1217
1480
|
}
|
|
1218
|
-
|
|
1481
|
+
|
|
1219
1482
|
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
|
1220
1483
|
childNode.add(this.options.textNodeName, tagContent);
|
|
1221
|
-
|
|
1222
|
-
this.addChild(currentNode, childNode, jPath);
|
|
1223
|
-
}else {
|
|
1224
|
-
|
|
1225
|
-
if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
|
|
1226
|
-
if(tagName[tagName.length - 1] === "/"){ //remove trailing '/'
|
|
1484
|
+
|
|
1485
|
+
this.addChild(currentNode, childNode, jPath, startIndex);
|
|
1486
|
+
} else {
|
|
1487
|
+
//selfClosing tag
|
|
1488
|
+
if (tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1) {
|
|
1489
|
+
if (tagName[tagName.length - 1] === "/") { //remove trailing '/'
|
|
1227
1490
|
tagName = tagName.substr(0, tagName.length - 1);
|
|
1228
1491
|
jPath = jPath.substr(0, jPath.length - 1);
|
|
1229
1492
|
tagExp = tagName;
|
|
1230
|
-
}else {
|
|
1493
|
+
} else {
|
|
1231
1494
|
tagExp = tagExp.substr(0, tagExp.length - 1);
|
|
1232
1495
|
}
|
|
1233
|
-
|
|
1234
|
-
if(this.options.transformTagName) {
|
|
1235
|
-
|
|
1496
|
+
|
|
1497
|
+
if (this.options.transformTagName) {
|
|
1498
|
+
const newTagName = this.options.transformTagName(tagName);
|
|
1499
|
+
if (tagExp === tagName) {
|
|
1500
|
+
tagExp = newTagName;
|
|
1501
|
+
}
|
|
1502
|
+
tagName = newTagName;
|
|
1236
1503
|
}
|
|
1237
1504
|
|
|
1238
|
-
const childNode = new
|
|
1239
|
-
if(tagName !== tagExp && attrExpPresent){
|
|
1505
|
+
const childNode = new XmlNode(tagName);
|
|
1506
|
+
if (tagName !== tagExp && attrExpPresent) {
|
|
1240
1507
|
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
|
|
1241
1508
|
}
|
|
1242
|
-
this.addChild(currentNode, childNode, jPath);
|
|
1509
|
+
this.addChild(currentNode, childNode, jPath, startIndex);
|
|
1243
1510
|
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
|
1244
1511
|
}
|
|
1245
|
-
|
|
1512
|
+
//opening tag
|
|
1246
1513
|
else {
|
|
1247
|
-
const childNode = new
|
|
1514
|
+
const childNode = new XmlNode(tagName);
|
|
1248
1515
|
this.tagsNodeStack.push(currentNode);
|
|
1249
|
-
|
|
1250
|
-
if(tagName !== tagExp && attrExpPresent){
|
|
1516
|
+
|
|
1517
|
+
if (tagName !== tagExp && attrExpPresent) {
|
|
1251
1518
|
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
|
|
1252
1519
|
}
|
|
1253
|
-
this.addChild(currentNode, childNode, jPath);
|
|
1520
|
+
this.addChild(currentNode, childNode, jPath, startIndex);
|
|
1254
1521
|
currentNode = childNode;
|
|
1255
1522
|
}
|
|
1256
1523
|
textData = "";
|
|
1257
1524
|
i = closeIndex;
|
|
1258
1525
|
}
|
|
1259
1526
|
}
|
|
1260
|
-
}else {
|
|
1527
|
+
} else {
|
|
1261
1528
|
textData += xmlData[i];
|
|
1262
1529
|
}
|
|
1263
1530
|
}
|
|
1264
1531
|
return xmlObj.child;
|
|
1265
1532
|
};
|
|
1266
1533
|
|
|
1267
|
-
function addChild(currentNode, childNode, jPath){
|
|
1534
|
+
function addChild(currentNode, childNode, jPath, startIndex) {
|
|
1535
|
+
// unset startIndex if not requested
|
|
1536
|
+
if (!this.options.captureMetaData) startIndex = undefined;
|
|
1268
1537
|
const result = this.options.updateTag(childNode.tagname, jPath, childNode[":@"]);
|
|
1269
|
-
if(result === false);else if(typeof result === "string"){
|
|
1538
|
+
if (result === false) ; else if (typeof result === "string") {
|
|
1270
1539
|
childNode.tagname = result;
|
|
1271
|
-
currentNode.addChild(childNode);
|
|
1272
|
-
}else {
|
|
1273
|
-
currentNode.addChild(childNode);
|
|
1540
|
+
currentNode.addChild(childNode, startIndex);
|
|
1541
|
+
} else {
|
|
1542
|
+
currentNode.addChild(childNode, startIndex);
|
|
1274
1543
|
}
|
|
1275
1544
|
}
|
|
1276
1545
|
|
|
1277
|
-
const replaceEntitiesValue$1 = function(val){
|
|
1546
|
+
const replaceEntitiesValue$1 = function (val, tagName, jPath) {
|
|
1547
|
+
// Performance optimization: Early return if no entities to replace
|
|
1548
|
+
if (val.indexOf('&') === -1) {
|
|
1549
|
+
return val;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
const entityConfig = this.options.processEntities;
|
|
1553
|
+
|
|
1554
|
+
if (!entityConfig.enabled) {
|
|
1555
|
+
return val;
|
|
1556
|
+
}
|
|
1278
1557
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
val
|
|
1558
|
+
// Check tag-specific filtering
|
|
1559
|
+
if (entityConfig.allowedTags) {
|
|
1560
|
+
if (!entityConfig.allowedTags.includes(tagName)) {
|
|
1561
|
+
return val; // Skip entity replacement for current tag as not set
|
|
1283
1562
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
if (entityConfig.tagFilter) {
|
|
1566
|
+
if (!entityConfig.tagFilter(tagName, jPath)) {
|
|
1567
|
+
return val; // Skip based on custom filter
|
|
1287
1568
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
// Replace DOCTYPE entities
|
|
1572
|
+
for (let entityName in this.docTypeEntities) {
|
|
1573
|
+
const entity = this.docTypeEntities[entityName];
|
|
1574
|
+
const matches = val.match(entity.regx);
|
|
1575
|
+
|
|
1576
|
+
if (matches) {
|
|
1577
|
+
// Track expansions
|
|
1578
|
+
this.entityExpansionCount += matches.length;
|
|
1579
|
+
|
|
1580
|
+
// Check expansion limit
|
|
1581
|
+
if (entityConfig.maxTotalExpansions &&
|
|
1582
|
+
this.entityExpansionCount > entityConfig.maxTotalExpansions) {
|
|
1583
|
+
throw new Error(
|
|
1584
|
+
`Entity expansion limit exceeded: ${this.entityExpansionCount} > ${entityConfig.maxTotalExpansions}`
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// Store length before replacement
|
|
1589
|
+
const lengthBefore = val.length;
|
|
1590
|
+
val = val.replace(entity.regx, entity.val);
|
|
1591
|
+
|
|
1592
|
+
// Check expanded length immediately after replacement
|
|
1593
|
+
if (entityConfig.maxExpandedLength) {
|
|
1594
|
+
this.currentExpandedLength += (val.length - lengthBefore);
|
|
1595
|
+
|
|
1596
|
+
if (this.currentExpandedLength > entityConfig.maxExpandedLength) {
|
|
1597
|
+
throw new Error(
|
|
1598
|
+
`Total expanded content size exceeded: ${this.currentExpandedLength} > ${entityConfig.maxExpandedLength}`
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1292
1601
|
}
|
|
1293
1602
|
}
|
|
1294
|
-
val = val.replace( this.ampEntity.regex, this.ampEntity.val);
|
|
1295
1603
|
}
|
|
1604
|
+
if (val.indexOf('&') === -1) return val; // Early exit
|
|
1605
|
+
|
|
1606
|
+
// Replace standard entities
|
|
1607
|
+
for (let entityName in this.lastEntities) {
|
|
1608
|
+
const entity = this.lastEntities[entityName];
|
|
1609
|
+
val = val.replace(entity.regex, entity.val);
|
|
1610
|
+
}
|
|
1611
|
+
if (val.indexOf('&') === -1) return val; // Early exit
|
|
1612
|
+
|
|
1613
|
+
// Replace HTML entities if enabled
|
|
1614
|
+
if (this.options.htmlEntities) {
|
|
1615
|
+
for (let entityName in this.htmlEntities) {
|
|
1616
|
+
const entity = this.htmlEntities[entityName];
|
|
1617
|
+
val = val.replace(entity.regex, entity.val);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
// Replace ampersand entity last
|
|
1622
|
+
val = val.replace(this.ampEntity.regex, this.ampEntity.val);
|
|
1623
|
+
|
|
1296
1624
|
return val;
|
|
1297
1625
|
};
|
|
1626
|
+
|
|
1627
|
+
|
|
1298
1628
|
function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) {
|
|
1299
1629
|
if (textData) { //store previously collected data as textNode
|
|
1300
|
-
if(isLeafNode === undefined) isLeafNode =
|
|
1301
|
-
|
|
1630
|
+
if (isLeafNode === undefined) isLeafNode = currentNode.child.length === 0;
|
|
1631
|
+
|
|
1302
1632
|
textData = this.parseTextData(textData,
|
|
1303
1633
|
currentNode.tagname,
|
|
1304
1634
|
jPath,
|
|
@@ -1315,17 +1645,14 @@ function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) {
|
|
|
1315
1645
|
|
|
1316
1646
|
//TODO: use jPath to simplify the logic
|
|
1317
1647
|
/**
|
|
1318
|
-
*
|
|
1319
|
-
* @param {
|
|
1648
|
+
* @param {Set} stopNodesExact
|
|
1649
|
+
* @param {Set} stopNodesWildcard
|
|
1320
1650
|
* @param {string} jPath
|
|
1321
|
-
* @param {string} currentTagName
|
|
1651
|
+
* @param {string} currentTagName
|
|
1322
1652
|
*/
|
|
1323
|
-
function isItStopNode(
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
const stopNodeExp = stopNodes[stopNodePath];
|
|
1327
|
-
if( allNodesExp === stopNodeExp || jPath === stopNodeExp ) return true;
|
|
1328
|
-
}
|
|
1653
|
+
function isItStopNode(stopNodesExact, stopNodesWildcard, jPath, currentTagName) {
|
|
1654
|
+
if (stopNodesWildcard && stopNodesWildcard.has(currentTagName)) return true;
|
|
1655
|
+
if (stopNodesExact && stopNodesExact.has(jPath)) return true;
|
|
1329
1656
|
return false;
|
|
1330
1657
|
}
|
|
1331
1658
|
|
|
@@ -1335,24 +1662,24 @@ function isItStopNode(stopNodes, jPath, currentTagName){
|
|
|
1335
1662
|
* @param {number} i starting index
|
|
1336
1663
|
* @returns
|
|
1337
1664
|
*/
|
|
1338
|
-
function tagExpWithClosingIndex(xmlData, i, closingChar = ">"){
|
|
1665
|
+
function tagExpWithClosingIndex(xmlData, i, closingChar = ">") {
|
|
1339
1666
|
let attrBoundary;
|
|
1340
1667
|
let tagExp = "";
|
|
1341
1668
|
for (let index = i; index < xmlData.length; index++) {
|
|
1342
1669
|
let ch = xmlData[index];
|
|
1343
1670
|
if (attrBoundary) {
|
|
1344
|
-
|
|
1671
|
+
if (ch === attrBoundary) attrBoundary = "";//reset
|
|
1345
1672
|
} else if (ch === '"' || ch === "'") {
|
|
1346
|
-
|
|
1673
|
+
attrBoundary = ch;
|
|
1347
1674
|
} else if (ch === closingChar[0]) {
|
|
1348
|
-
if(closingChar[1]){
|
|
1349
|
-
if(xmlData[index + 1] === closingChar[1]){
|
|
1675
|
+
if (closingChar[1]) {
|
|
1676
|
+
if (xmlData[index + 1] === closingChar[1]) {
|
|
1350
1677
|
return {
|
|
1351
1678
|
data: tagExp,
|
|
1352
1679
|
index: index
|
|
1353
1680
|
}
|
|
1354
1681
|
}
|
|
1355
|
-
}else {
|
|
1682
|
+
} else {
|
|
1356
1683
|
return {
|
|
1357
1684
|
data: tagExp,
|
|
1358
1685
|
index: index
|
|
@@ -1365,33 +1692,33 @@ function tagExpWithClosingIndex(xmlData, i, closingChar = ">"){
|
|
|
1365
1692
|
}
|
|
1366
1693
|
}
|
|
1367
1694
|
|
|
1368
|
-
function findClosingIndex(xmlData, str, i, errMsg){
|
|
1695
|
+
function findClosingIndex(xmlData, str, i, errMsg) {
|
|
1369
1696
|
const closingIndex = xmlData.indexOf(str, i);
|
|
1370
|
-
if(closingIndex === -1){
|
|
1697
|
+
if (closingIndex === -1) {
|
|
1371
1698
|
throw new Error(errMsg)
|
|
1372
|
-
}else {
|
|
1699
|
+
} else {
|
|
1373
1700
|
return closingIndex + str.length - 1;
|
|
1374
1701
|
}
|
|
1375
1702
|
}
|
|
1376
1703
|
|
|
1377
|
-
function readTagExp(xmlData,i, removeNSPrefix, closingChar = ">"){
|
|
1378
|
-
const result = tagExpWithClosingIndex(xmlData, i+1, closingChar);
|
|
1379
|
-
if(!result) return;
|
|
1704
|
+
function readTagExp(xmlData, i, removeNSPrefix, closingChar = ">") {
|
|
1705
|
+
const result = tagExpWithClosingIndex(xmlData, i + 1, closingChar);
|
|
1706
|
+
if (!result) return;
|
|
1380
1707
|
let tagExp = result.data;
|
|
1381
1708
|
const closeIndex = result.index;
|
|
1382
1709
|
const separatorIndex = tagExp.search(/\s/);
|
|
1383
1710
|
let tagName = tagExp;
|
|
1384
1711
|
let attrExpPresent = true;
|
|
1385
|
-
if(separatorIndex !== -1){//separate tag name and attributes expression
|
|
1712
|
+
if (separatorIndex !== -1) {//separate tag name and attributes expression
|
|
1386
1713
|
tagName = tagExp.substring(0, separatorIndex);
|
|
1387
1714
|
tagExp = tagExp.substring(separatorIndex + 1).trimStart();
|
|
1388
1715
|
}
|
|
1389
1716
|
|
|
1390
1717
|
const rawTagName = tagName;
|
|
1391
|
-
if(removeNSPrefix){
|
|
1718
|
+
if (removeNSPrefix) {
|
|
1392
1719
|
const colonIndex = tagName.indexOf(":");
|
|
1393
|
-
if(colonIndex !== -1){
|
|
1394
|
-
tagName = tagName.substr(colonIndex+1);
|
|
1720
|
+
if (colonIndex !== -1) {
|
|
1721
|
+
tagName = tagName.substr(colonIndex + 1);
|
|
1395
1722
|
attrExpPresent = tagName !== result.data.substr(colonIndex + 1);
|
|
1396
1723
|
}
|
|
1397
1724
|
}
|
|
@@ -1410,47 +1737,47 @@ function readTagExp(xmlData,i, removeNSPrefix, closingChar = ">"){
|
|
|
1410
1737
|
* @param {string} tagName
|
|
1411
1738
|
* @param {number} i
|
|
1412
1739
|
*/
|
|
1413
|
-
function readStopNodeData(xmlData, tagName, i){
|
|
1740
|
+
function readStopNodeData(xmlData, tagName, i) {
|
|
1414
1741
|
const startIndex = i;
|
|
1415
1742
|
// Starting at 1 since we already have an open tag
|
|
1416
1743
|
let openTagCount = 1;
|
|
1417
1744
|
|
|
1418
1745
|
for (; i < xmlData.length; i++) {
|
|
1419
|
-
if(
|
|
1420
|
-
if (xmlData[i+1] === "/") {//close tag
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
}
|
|
1746
|
+
if (xmlData[i] === "<") {
|
|
1747
|
+
if (xmlData[i + 1] === "/") {//close tag
|
|
1748
|
+
const closeIndex = findClosingIndex(xmlData, ">", i, `${tagName} is not closed`);
|
|
1749
|
+
let closeTagName = xmlData.substring(i + 2, closeIndex).trim();
|
|
1750
|
+
if (closeTagName === tagName) {
|
|
1751
|
+
openTagCount--;
|
|
1752
|
+
if (openTagCount === 0) {
|
|
1753
|
+
return {
|
|
1754
|
+
tagContent: xmlData.substring(startIndex, i),
|
|
1755
|
+
i: closeIndex
|
|
1430
1756
|
}
|
|
1431
1757
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1758
|
+
}
|
|
1759
|
+
i = closeIndex;
|
|
1760
|
+
} else if (xmlData[i + 1] === '?') {
|
|
1761
|
+
const closeIndex = findClosingIndex(xmlData, "?>", i + 1, "StopNode is not closed.");
|
|
1762
|
+
i = closeIndex;
|
|
1763
|
+
} else if (xmlData.substr(i + 1, 3) === '!--') {
|
|
1764
|
+
const closeIndex = findClosingIndex(xmlData, "-->", i + 3, "StopNode is not closed.");
|
|
1765
|
+
i = closeIndex;
|
|
1766
|
+
} else if (xmlData.substr(i + 1, 2) === '![') {
|
|
1767
|
+
const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
|
|
1768
|
+
i = closeIndex;
|
|
1769
|
+
} else {
|
|
1770
|
+
const tagData = readTagExp(xmlData, i, '>');
|
|
1444
1771
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
}
|
|
1450
|
-
i=tagData.closeIndex;
|
|
1772
|
+
if (tagData) {
|
|
1773
|
+
const openTagName = tagData && tagData.tagName;
|
|
1774
|
+
if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length - 1] !== "/") {
|
|
1775
|
+
openTagCount++;
|
|
1451
1776
|
}
|
|
1777
|
+
i = tagData.closeIndex;
|
|
1452
1778
|
}
|
|
1453
1779
|
}
|
|
1780
|
+
}
|
|
1454
1781
|
}//end for loop
|
|
1455
1782
|
}
|
|
1456
1783
|
|
|
@@ -1458,11 +1785,11 @@ function parseValue(val, shouldParse, options) {
|
|
|
1458
1785
|
if (shouldParse && typeof val === 'string') {
|
|
1459
1786
|
//console.log(options)
|
|
1460
1787
|
const newval = val.trim();
|
|
1461
|
-
if(newval === 'true'
|
|
1462
|
-
else if(newval === 'false'
|
|
1788
|
+
if (newval === 'true') return true;
|
|
1789
|
+
else if (newval === 'false') return false;
|
|
1463
1790
|
else return toNumber(val, options);
|
|
1464
1791
|
} else {
|
|
1465
|
-
if (
|
|
1792
|
+
if (isExist(val)) {
|
|
1466
1793
|
return val;
|
|
1467
1794
|
} else {
|
|
1468
1795
|
return '';
|
|
@@ -1470,10 +1797,17 @@ function parseValue(val, shouldParse, options) {
|
|
|
1470
1797
|
}
|
|
1471
1798
|
}
|
|
1472
1799
|
|
|
1800
|
+
function fromCodePoint(str, base, prefix) {
|
|
1801
|
+
const codePoint = Number.parseInt(str, base);
|
|
1473
1802
|
|
|
1474
|
-
|
|
1803
|
+
if (codePoint >= 0 && codePoint <= 0x10FFFF) {
|
|
1804
|
+
return String.fromCodePoint(codePoint);
|
|
1805
|
+
} else {
|
|
1806
|
+
return prefix + str + ";";
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1475
1809
|
|
|
1476
|
-
|
|
1810
|
+
const METADATA_SYMBOL = XmlNode.getMetaDataSymbol();
|
|
1477
1811
|
|
|
1478
1812
|
/**
|
|
1479
1813
|
*
|
|
@@ -1481,7 +1815,7 @@ var node2json = {};
|
|
|
1481
1815
|
* @param {any} options
|
|
1482
1816
|
* @returns
|
|
1483
1817
|
*/
|
|
1484
|
-
function prettify
|
|
1818
|
+
function prettify(node, options){
|
|
1485
1819
|
return compress( node, options);
|
|
1486
1820
|
}
|
|
1487
1821
|
|
|
@@ -1511,6 +1845,9 @@ function compress(arr, options, jPath){
|
|
|
1511
1845
|
|
|
1512
1846
|
let val = compress(tagObj[property], options, newJpath);
|
|
1513
1847
|
const isLeaf = isLeafTag(val, options);
|
|
1848
|
+
if (tagObj[METADATA_SYMBOL] !== undefined) {
|
|
1849
|
+
val[METADATA_SYMBOL] = tagObj[METADATA_SYMBOL]; // copy over metadata
|
|
1850
|
+
}
|
|
1514
1851
|
|
|
1515
1852
|
if(tagObj[":@"]){
|
|
1516
1853
|
assignAttributes( val, tagObj[":@"], newJpath, options);
|
|
@@ -1585,14 +1922,8 @@ function isLeafTag(obj, options){
|
|
|
1585
1922
|
|
|
1586
1923
|
return false;
|
|
1587
1924
|
}
|
|
1588
|
-
node2json.prettify = prettify$1;
|
|
1589
1925
|
|
|
1590
|
-
|
|
1591
|
-
const OrderedObjParser = OrderedObjParser_1;
|
|
1592
|
-
const { prettify} = node2json;
|
|
1593
|
-
const validator$1 = validator$2;
|
|
1594
|
-
|
|
1595
|
-
let XMLParser$1 = class XMLParser{
|
|
1926
|
+
class XMLParser{
|
|
1596
1927
|
|
|
1597
1928
|
constructor(options){
|
|
1598
1929
|
this.externalEntities = {};
|
|
@@ -1601,19 +1932,20 @@ let XMLParser$1 = class XMLParser{
|
|
|
1601
1932
|
}
|
|
1602
1933
|
/**
|
|
1603
1934
|
* Parse XML dats to JS object
|
|
1604
|
-
* @param {string|
|
|
1935
|
+
* @param {string|Uint8Array} xmlData
|
|
1605
1936
|
* @param {boolean|Object} validationOption
|
|
1606
1937
|
*/
|
|
1607
1938
|
parse(xmlData,validationOption){
|
|
1608
|
-
if(typeof xmlData
|
|
1939
|
+
if(typeof xmlData !== "string" && xmlData.toString){
|
|
1609
1940
|
xmlData = xmlData.toString();
|
|
1610
|
-
}else {
|
|
1941
|
+
}else if(typeof xmlData !== "string"){
|
|
1611
1942
|
throw new Error("XML data is accepted in String or Bytes[] form.")
|
|
1612
1943
|
}
|
|
1944
|
+
|
|
1613
1945
|
if( validationOption){
|
|
1614
1946
|
if(validationOption === true) validationOption = {}; //validate with default options
|
|
1615
1947
|
|
|
1616
|
-
const result =
|
|
1948
|
+
const result = validate(xmlData, validationOption);
|
|
1617
1949
|
if (result !== true) {
|
|
1618
1950
|
throw Error( `${result.err.msg}:${result.err.line}:${result.err.col}` )
|
|
1619
1951
|
}
|
|
@@ -1641,9 +1973,21 @@ let XMLParser$1 = class XMLParser{
|
|
|
1641
1973
|
this.externalEntities[key] = value;
|
|
1642
1974
|
}
|
|
1643
1975
|
}
|
|
1644
|
-
};
|
|
1645
1976
|
|
|
1646
|
-
|
|
1977
|
+
/**
|
|
1978
|
+
* Returns a Symbol that can be used to access the metadata
|
|
1979
|
+
* property on a node.
|
|
1980
|
+
*
|
|
1981
|
+
* If Symbol is not available in the environment, an ordinary property is used
|
|
1982
|
+
* and the name of the property is here returned.
|
|
1983
|
+
*
|
|
1984
|
+
* The XMLMetaData property is only present when `captureMetaData`
|
|
1985
|
+
* is true in the options.
|
|
1986
|
+
*/
|
|
1987
|
+
static getMetaDataSymbol() {
|
|
1988
|
+
return XmlNode.getMetaDataSymbol();
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1647
1991
|
|
|
1648
1992
|
const EOL = "\n";
|
|
1649
1993
|
|
|
@@ -1779,11 +2123,6 @@ function replaceEntitiesValue(textValue, options) {
|
|
|
1779
2123
|
}
|
|
1780
2124
|
return textValue;
|
|
1781
2125
|
}
|
|
1782
|
-
var orderedJs2Xml = toXml;
|
|
1783
|
-
|
|
1784
|
-
//parse Empty Node as self closing node
|
|
1785
|
-
const buildFromOrderedJs = orderedJs2Xml;
|
|
1786
|
-
const getIgnoreAttributesFn = ignoreAttributes;
|
|
1787
2126
|
|
|
1788
2127
|
const defaultOptions = {
|
|
1789
2128
|
attributeNamePrefix: '@_',
|
|
@@ -1848,7 +2187,7 @@ function Builder(options) {
|
|
|
1848
2187
|
|
|
1849
2188
|
Builder.prototype.build = function(jObj) {
|
|
1850
2189
|
if(this.options.preserveOrder){
|
|
1851
|
-
return
|
|
2190
|
+
return toXml(jObj, this.options);
|
|
1852
2191
|
}else {
|
|
1853
2192
|
if(Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1){
|
|
1854
2193
|
jObj = {
|
|
@@ -1874,6 +2213,8 @@ Builder.prototype.j2x = function(jObj, level, ajPath) {
|
|
|
1874
2213
|
// null attribute should be ignored by the attribute list, but should not cause the tag closing
|
|
1875
2214
|
if (this.isAttribute(key)) {
|
|
1876
2215
|
val += '';
|
|
2216
|
+
} else if (key === this.options.cdataPropName) {
|
|
2217
|
+
val += '';
|
|
1877
2218
|
} else if (key[0] === '?') {
|
|
1878
2219
|
val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
|
|
1879
2220
|
} else {
|
|
@@ -2049,17 +2390,54 @@ function isAttribute(name /*, options*/) {
|
|
|
2049
2390
|
}
|
|
2050
2391
|
}
|
|
2051
2392
|
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
XMLValidator: validator,
|
|
2061
|
-
XMLBuilder: XMLBuilder
|
|
2393
|
+
const ISO20022Messages = {
|
|
2394
|
+
CAMT_003: 'CAMT.003',
|
|
2395
|
+
CAMT_004: 'CAMT.004',
|
|
2396
|
+
CAMT_005: 'CAMT.005',
|
|
2397
|
+
CAMT_006: 'CAMT.006',
|
|
2398
|
+
CAMT_053: 'CAMT.053',
|
|
2399
|
+
PAIN_001: 'PAIN.001',
|
|
2400
|
+
PAIN_002: 'PAIN.002',
|
|
2062
2401
|
};
|
|
2402
|
+
const ISO20022Implementations = new Map();
|
|
2403
|
+
function registerISO20022Implementation(cl) {
|
|
2404
|
+
cl.supportedMessages().forEach(msg => {
|
|
2405
|
+
ISO20022Implementations.set(msg, cl);
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
function getISO20022Implementation(type) {
|
|
2409
|
+
return ISO20022Implementations.get(type);
|
|
2410
|
+
}
|
|
2411
|
+
class XML {
|
|
2412
|
+
/**
|
|
2413
|
+
* Creates and configures the XML Parser
|
|
2414
|
+
*
|
|
2415
|
+
* @returns {XMLParser} A configured instance of XMLParser
|
|
2416
|
+
*/
|
|
2417
|
+
static getParser() {
|
|
2418
|
+
return new XMLParser({
|
|
2419
|
+
ignoreAttributes: false,
|
|
2420
|
+
attributeNamePrefix: '@_',
|
|
2421
|
+
textNodeName: '#text',
|
|
2422
|
+
/**
|
|
2423
|
+
* Disable automatic numeric parsing. ISO 20022 fields are semantically
|
|
2424
|
+
* strings (Max35Text, etc.). Numeric-looking values like AcctSvcrRef,
|
|
2425
|
+
* EndToEndId, NtryRef, and Cd must stay as strings to preserve leading
|
|
2426
|
+
* zeros and avoid precision loss on large numbers. Amounts are explicitly
|
|
2427
|
+
* converted to numbers downstream via parseAmountToMinorUnits.
|
|
2428
|
+
*/
|
|
2429
|
+
parseTagValue: false,
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
static getBuilder() {
|
|
2433
|
+
return new Builder({
|
|
2434
|
+
ignoreAttributes: false,
|
|
2435
|
+
attributeNamePrefix: '@_',
|
|
2436
|
+
textNodeName: '#text',
|
|
2437
|
+
format: true,
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2063
2441
|
|
|
2064
2442
|
/**
|
|
2065
2443
|
* Base error class for all ISO 20022 related errors in the library.
|
|
@@ -7405,7 +7783,7 @@ class PaymentInitiation {
|
|
|
7405
7783
|
return this.serialize();
|
|
7406
7784
|
}
|
|
7407
7785
|
static getBuilder() {
|
|
7408
|
-
return new
|
|
7786
|
+
return new Builder({
|
|
7409
7787
|
ignoreAttributes: false,
|
|
7410
7788
|
attributeNamePrefix: '@',
|
|
7411
7789
|
textNodeName: '#',
|
|
@@ -7513,7 +7891,7 @@ class SWIFTCreditPaymentInitiation extends PaymentInitiation {
|
|
|
7513
7891
|
* @returns {string} The XML representation of the payment initiation.
|
|
7514
7892
|
*/
|
|
7515
7893
|
static fromXML(rawXml) {
|
|
7516
|
-
const parser =
|
|
7894
|
+
const parser = XML.getParser();
|
|
7517
7895
|
const xml = parser.parse(rawXml);
|
|
7518
7896
|
if (!xml.Document) {
|
|
7519
7897
|
throw new InvalidXmlError('Invalid XML format');
|
|
@@ -7808,7 +8186,7 @@ class SEPACreditPaymentInitiation extends PaymentInitiation {
|
|
|
7808
8186
|
return builder.build(xml);
|
|
7809
8187
|
}
|
|
7810
8188
|
static fromXML(rawXml) {
|
|
7811
|
-
const parser =
|
|
8189
|
+
const parser = XML.getParser();
|
|
7812
8190
|
const xml = parser.parse(rawXml);
|
|
7813
8191
|
if (!xml.Document) {
|
|
7814
8192
|
throw new InvalidXmlError('Invalid XML format');
|
|
@@ -8121,7 +8499,7 @@ class SEPAMultiCreditPaymentInitiation extends PaymentInitiation {
|
|
|
8121
8499
|
* @throws {InvalidXmlNamespaceError} If the namespace is not pain.001.001.03.
|
|
8122
8500
|
*/
|
|
8123
8501
|
static fromXML(rawXml) {
|
|
8124
|
-
const parser =
|
|
8502
|
+
const parser = XML.getParser();
|
|
8125
8503
|
const xml = parser.parse(rawXml);
|
|
8126
8504
|
// Validate XML structure
|
|
8127
8505
|
if (!xml.Document) {
|
|
@@ -8400,7 +8778,7 @@ class RTPCreditPaymentInitiation extends PaymentInitiation {
|
|
|
8400
8778
|
return builder.build(xml);
|
|
8401
8779
|
}
|
|
8402
8780
|
static fromXML(rawXml) {
|
|
8403
|
-
const parser =
|
|
8781
|
+
const parser = XML.getParser();
|
|
8404
8782
|
const xml = parser.parse(rawXml);
|
|
8405
8783
|
if (!xml.Document) {
|
|
8406
8784
|
throw new InvalidXmlError('Invalid XML format');
|
|
@@ -8737,11 +9115,7 @@ class ACHCreditPaymentInitiation extends PaymentInitiation {
|
|
|
8737
9115
|
* @throws {Error} If multiple payment information blocks are found.
|
|
8738
9116
|
*/
|
|
8739
9117
|
static fromXML(rawXml) {
|
|
8740
|
-
const parser =
|
|
8741
|
-
ignoreAttributes: false,
|
|
8742
|
-
attributeNamePrefix: '@_',
|
|
8743
|
-
textNodeName: '#text',
|
|
8744
|
-
});
|
|
9118
|
+
const parser = XML.getParser();
|
|
8745
9119
|
const xml = parser.parse(rawXml);
|
|
8746
9120
|
if (!xml.Document) {
|
|
8747
9121
|
throw new InvalidXmlError('Invalid XML format');
|
|
@@ -9103,7 +9477,7 @@ class SEPADirectDebitPaymentInitiation extends PaymentInitiation {
|
|
|
9103
9477
|
* @throws {InvalidXmlNamespaceError} If the namespace is not pain.008.
|
|
9104
9478
|
*/
|
|
9105
9479
|
static fromXML(rawXml) {
|
|
9106
|
-
const parser =
|
|
9480
|
+
const parser = XML.getParser();
|
|
9107
9481
|
const xml = parser.parse(rawXml);
|
|
9108
9482
|
// Validate XML structure
|
|
9109
9483
|
if (!xml.Document) {
|
|
@@ -9227,59 +9601,6 @@ class SEPADirectDebitPaymentInitiation extends PaymentInitiation {
|
|
|
9227
9601
|
}
|
|
9228
9602
|
}
|
|
9229
9603
|
|
|
9230
|
-
const ISO20022Messages = {
|
|
9231
|
-
CAMT_003: 'CAMT.003',
|
|
9232
|
-
CAMT_004: 'CAMT.004',
|
|
9233
|
-
CAMT_005: 'CAMT.005',
|
|
9234
|
-
CAMT_006: 'CAMT.006',
|
|
9235
|
-
CAMT_053: 'CAMT.053',
|
|
9236
|
-
PAIN_001: 'PAIN.001',
|
|
9237
|
-
PAIN_002: 'PAIN.002',
|
|
9238
|
-
};
|
|
9239
|
-
const ISO20022Implementations = new Map();
|
|
9240
|
-
function registerISO20022Implementation(cl) {
|
|
9241
|
-
cl.supportedMessages().forEach(msg => {
|
|
9242
|
-
ISO20022Implementations.set(msg, cl);
|
|
9243
|
-
});
|
|
9244
|
-
}
|
|
9245
|
-
function getISO20022Implementation(type) {
|
|
9246
|
-
return ISO20022Implementations.get(type);
|
|
9247
|
-
}
|
|
9248
|
-
class XML {
|
|
9249
|
-
/**
|
|
9250
|
-
* Creates and configures the XML Parser
|
|
9251
|
-
*
|
|
9252
|
-
* @returns {XMLParser} A configured instance of XMLParser
|
|
9253
|
-
*/
|
|
9254
|
-
static getParser() {
|
|
9255
|
-
return new fxp.XMLParser({
|
|
9256
|
-
ignoreAttributes: false,
|
|
9257
|
-
attributeNamePrefix: '@_',
|
|
9258
|
-
textNodeName: '#text',
|
|
9259
|
-
tagValueProcessor: (tagName, tagValue, _jPath, _hasAttributes, isLeafNode) => {
|
|
9260
|
-
/**
|
|
9261
|
-
* Codes and Entry References can look like numbers and get parsed
|
|
9262
|
-
* appropriately. We don't want this to happen, as they contain leading
|
|
9263
|
-
* zeros or are too long and overflow.
|
|
9264
|
-
*
|
|
9265
|
-
* Ex. <Cd>0001234<Cd> Should resolve to "0001234"
|
|
9266
|
-
*/
|
|
9267
|
-
if (isLeafNode && ['Cd', 'NtryRef'].includes(tagName))
|
|
9268
|
-
return undefined;
|
|
9269
|
-
return tagValue;
|
|
9270
|
-
},
|
|
9271
|
-
});
|
|
9272
|
-
}
|
|
9273
|
-
static getBuilder() {
|
|
9274
|
-
return new fxp.XMLBuilder({
|
|
9275
|
-
ignoreAttributes: false,
|
|
9276
|
-
attributeNamePrefix: '@_',
|
|
9277
|
-
textNodeName: '#text',
|
|
9278
|
-
format: true,
|
|
9279
|
-
});
|
|
9280
|
-
}
|
|
9281
|
-
}
|
|
9282
|
-
|
|
9283
9604
|
class CashManagementGetAccount {
|
|
9284
9605
|
_data;
|
|
9285
9606
|
constructor(data) {
|
|
@@ -9461,8 +9782,8 @@ registerISO20022Implementation(CashManagementGetAccount);
|
|
|
9461
9782
|
|
|
9462
9783
|
const parseStatement = (stmt) => {
|
|
9463
9784
|
const id = stmt.Id.toString();
|
|
9464
|
-
const electronicSequenceNumber = stmt.ElctrncSeqNb;
|
|
9465
|
-
const legalSequenceNumber = stmt.LglSeqNb;
|
|
9785
|
+
const electronicSequenceNumber = stmt.ElctrncSeqNb ? Number(stmt.ElctrncSeqNb) : undefined;
|
|
9786
|
+
const legalSequenceNumber = stmt.LglSeqNb ? Number(stmt.LglSeqNb) : undefined;
|
|
9466
9787
|
const creationDate = new Date(stmt.CreDtTm);
|
|
9467
9788
|
let fromDate;
|
|
9468
9789
|
let toDate;
|
|
@@ -9471,18 +9792,18 @@ const parseStatement = (stmt) => {
|
|
|
9471
9792
|
toDate = new Date(stmt.FrToDt.ToDtTm);
|
|
9472
9793
|
}
|
|
9473
9794
|
// Txn Summaries
|
|
9474
|
-
const numOfEntries = stmt.TxsSummry?.TtlNtries.NbOfNtries;
|
|
9475
|
-
const sumOfEntries = stmt.TxsSummry?.TtlNtries.Sum;
|
|
9795
|
+
const numOfEntries = stmt.TxsSummry?.TtlNtries.NbOfNtries != null ? Number(stmt.TxsSummry.TtlNtries.NbOfNtries) : undefined;
|
|
9796
|
+
const sumOfEntries = stmt.TxsSummry?.TtlNtries.Sum != null ? Number(stmt.TxsSummry.TtlNtries.Sum) : undefined;
|
|
9476
9797
|
const rawNetAmountOfEntries = stmt.TxsSummry?.TtlNtries.TtlNetNtryAmt;
|
|
9477
9798
|
let netAmountOfEntries;
|
|
9478
9799
|
// No currency information, default to USD
|
|
9479
9800
|
if (rawNetAmountOfEntries) {
|
|
9480
9801
|
netAmountOfEntries = parseAmountToMinorUnits(rawNetAmountOfEntries);
|
|
9481
9802
|
}
|
|
9482
|
-
const numOfCreditEntries = stmt.TxsSummry?.TtlCdtNtries.NbOfNtries;
|
|
9483
|
-
const sumOfCreditEntries = stmt.TxsSummry?.TtlCdtNtries.Sum;
|
|
9484
|
-
const numOfDebitEntries = stmt.TxsSummry?.TtlDbtNtries.NbOfNtries;
|
|
9485
|
-
const sumOfDebitEntries = stmt.TxsSummry?.TtlDbtNtries.Sum;
|
|
9803
|
+
const numOfCreditEntries = stmt.TxsSummry?.TtlCdtNtries.NbOfNtries != null ? Number(stmt.TxsSummry.TtlCdtNtries.NbOfNtries) : undefined;
|
|
9804
|
+
const sumOfCreditEntries = stmt.TxsSummry?.TtlCdtNtries.Sum != null ? Number(stmt.TxsSummry.TtlCdtNtries.Sum) : undefined;
|
|
9805
|
+
const numOfDebitEntries = stmt.TxsSummry?.TtlDbtNtries.NbOfNtries != null ? Number(stmt.TxsSummry.TtlDbtNtries.NbOfNtries) : undefined;
|
|
9806
|
+
const sumOfDebitEntries = stmt.TxsSummry?.TtlDbtNtries.Sum != null ? Number(stmt.TxsSummry.TtlDbtNtries.Sum) : undefined;
|
|
9486
9807
|
// Get account information
|
|
9487
9808
|
// TODO: Save account types here
|
|
9488
9809
|
const account = parseAccount(stmt.Acct);
|
|
@@ -9627,7 +9948,7 @@ const parseEntry = (entry) => {
|
|
|
9627
9948
|
const referenceId = entry.NtryRef;
|
|
9628
9949
|
const creditDebitIndicator = entry.CdtDbtInd === 'CRDT' ? 'credit' : 'debit';
|
|
9629
9950
|
const bookingDate = parseDate(entry.BookgDt);
|
|
9630
|
-
const reversal = entry.RvslInd === true;
|
|
9951
|
+
const reversal = entry.RvslInd === true || entry.RvslInd === 'true';
|
|
9631
9952
|
const rawAmount = entry.Amt['#text'];
|
|
9632
9953
|
const currency = entry.Amt['@_Ccy'];
|
|
9633
9954
|
const amount = parseAmountToMinorUnits(rawAmount, currency);
|
|
@@ -10790,7 +11111,7 @@ class PaymentStatusReport {
|
|
|
10790
11111
|
* @returns {PaymentStatusReport} A new PaymentStatusReport instance.
|
|
10791
11112
|
*/
|
|
10792
11113
|
static fromXML(rawXml) {
|
|
10793
|
-
const parser =
|
|
11114
|
+
const parser = XML.getParser();
|
|
10794
11115
|
const xml = parser.parse(rawXml);
|
|
10795
11116
|
const customerPaymentStatusReport = xml.Document.CstmrPmtStsRpt;
|
|
10796
11117
|
const rawCreationDate = customerPaymentStatusReport.GrpHdr.CreDtTm;
|