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