Ajout du choix des utilisateurs sur un événement. Ajout de fichiers dans un événement. (dropzone cassée)
This commit is contained in:
93
em2rp/node_modules/fast-xml-parser/src/cli/cli.js
generated
vendored
Normal file
93
em2rp/node_modules/fast-xml-parser/src/cli/cli.js
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
/*eslint-disable no-console*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const {XMLParser, XMLValidator} = require("../fxp");
|
||||
const readToEnd = require('./read').readToEnd;
|
||||
|
||||
const version = require('./../../package.json').version;
|
||||
if (process.argv[2] === '--help' || process.argv[2] === '-h') {
|
||||
console.log(require("./man"));
|
||||
} else if (process.argv[2] === '--version') {
|
||||
console.log(version);
|
||||
} else {
|
||||
const options = {
|
||||
removeNSPrefix: true,
|
||||
ignoreAttributes: false,
|
||||
parseTagValue: true,
|
||||
parseAttributeValue: true,
|
||||
};
|
||||
let fileName = '';
|
||||
let outputFileName;
|
||||
let validate = false;
|
||||
let validateOnly = false;
|
||||
for (let i = 2; i < process.argv.length; i++) {
|
||||
if (process.argv[i] === '-ns') {
|
||||
options.removeNSPrefix = false;
|
||||
} else if (process.argv[i] === '-a') {
|
||||
options.ignoreAttributes = true;
|
||||
} else if (process.argv[i] === '-c') {
|
||||
options.parseTagValue = false;
|
||||
options.parseAttributeValue = false;
|
||||
} else if (process.argv[i] === '-o') {
|
||||
outputFileName = process.argv[++i];
|
||||
} else if (process.argv[i] === '-v') {
|
||||
validate = true;
|
||||
} else if (process.argv[i] === '-V') {
|
||||
validateOnly = true;
|
||||
} else {
|
||||
//filename
|
||||
fileName = process.argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
const callback = function(xmlData) {
|
||||
let output = '';
|
||||
if (validate) {
|
||||
const parser = new XMLParser(options);
|
||||
output = parser.parse(xmlData,validate);
|
||||
} else if (validateOnly) {
|
||||
output = XMLValidator.validate(xmlData);
|
||||
process.exitCode = output === true ? 0 : 1;
|
||||
} else {
|
||||
const parser = new XMLParser(options);
|
||||
output = JSON.stringify(parser.parse(xmlData,validate), null, 4);
|
||||
}
|
||||
if (outputFileName) {
|
||||
writeToFile(outputFileName, output);
|
||||
} else {
|
||||
console.log(JSON.stringify(output, null, 2));
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
if (!fileName) {
|
||||
readToEnd(process.stdin, function(err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
callback(data.toString());
|
||||
});
|
||||
} else {
|
||||
fs.readFile(fileName, function(err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
callback(data.toString());
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Seems an invalid file or stream.' + e);
|
||||
}
|
||||
}
|
||||
|
||||
function writeToFile(fileName, data) {
|
||||
fs.writeFile(fileName, data, function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
console.log('JSON output has been written to ' + fileName);
|
||||
});
|
||||
}
|
12
em2rp/node_modules/fast-xml-parser/src/cli/man.js
generated
vendored
Normal file
12
em2rp/node_modules/fast-xml-parser/src/cli/man.js
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
module.exports = `Fast XML Parser 4.0.0
|
||||
----------------
|
||||
$ fxparser [-ns|-a|-c|-v|-V] <filename> [-o outputfile.json]
|
||||
$ cat xmlfile.xml | fxparser [-ns|-a|-c|-v|-V] [-o outputfile.json]
|
||||
|
||||
Options
|
||||
----------------
|
||||
-ns: remove namespace from tag and atrribute name.
|
||||
-a: don't parse attributes.
|
||||
-c: parse values to premitive type.
|
||||
-v: validate before parsing.
|
||||
-V: validate only.`
|
92
em2rp/node_modules/fast-xml-parser/src/cli/read.js
generated
vendored
Normal file
92
em2rp/node_modules/fast-xml-parser/src/cli/read.js
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
|
||||
// Copyright 2013 Timothy J Fontaine <tjfontaine@gmail.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the 'Software'), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE
|
||||
|
||||
/*
|
||||
|
||||
Read any stream all the way to the end and trigger a single cb
|
||||
|
||||
const http = require('http');
|
||||
|
||||
const rte = require('readtoend');
|
||||
|
||||
http.get('http://nodejs.org', function(response) {
|
||||
rte.readToEnd(response, function(err, body) {
|
||||
console.log(body);
|
||||
});
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
let stream = require('stream');
|
||||
const util = require('util');
|
||||
|
||||
if (!stream.Transform) {
|
||||
stream = require('readable-stream');
|
||||
}
|
||||
|
||||
function ReadToEnd(opts) {
|
||||
if (!(this instanceof ReadToEnd)) {
|
||||
return new ReadToEnd(opts);
|
||||
}
|
||||
|
||||
stream.Transform.call(this, opts);
|
||||
|
||||
this._rte_encoding = opts.encoding || 'utf8';
|
||||
|
||||
this._buff = '';
|
||||
}
|
||||
|
||||
module.exports = ReadToEnd;
|
||||
util.inherits(ReadToEnd, stream.Transform);
|
||||
|
||||
ReadToEnd.prototype._transform = function(chunk, encoding, done) {
|
||||
this._buff += chunk.toString(this._rte_encoding);
|
||||
this.push(chunk);
|
||||
done();
|
||||
};
|
||||
|
||||
ReadToEnd.prototype._flush = function(done) {
|
||||
this.emit('complete', undefined, this._buff);
|
||||
done();
|
||||
};
|
||||
|
||||
ReadToEnd.readToEnd = function(stream, options, cb) {
|
||||
if (!cb) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
const dest = new ReadToEnd(options);
|
||||
|
||||
stream.pipe(dest);
|
||||
|
||||
stream.on('error', function(err) {
|
||||
stream.unpipe(dest);
|
||||
cb(err);
|
||||
});
|
||||
|
||||
dest.on('complete', cb);
|
||||
|
||||
dest.resume();
|
||||
|
||||
return dest;
|
||||
};
|
418
em2rp/node_modules/fast-xml-parser/src/fxp.d.ts
generated
vendored
Normal file
418
em2rp/node_modules/fast-xml-parser/src/fxp.d.ts
generated
vendored
Normal file
@ -0,0 +1,418 @@
|
||||
type X2jOptions = {
|
||||
/**
|
||||
* Preserve the order of tags in resulting JS object
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
preserveOrder?: boolean;
|
||||
|
||||
/**
|
||||
* Give a prefix to the attribute name in the resulting JS object
|
||||
*
|
||||
* Defaults to '@_'
|
||||
*/
|
||||
attributeNamePrefix?: string;
|
||||
|
||||
/**
|
||||
* A name to group all attributes of a tag under, or `false` to disable
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
attributesGroupName?: false | string;
|
||||
|
||||
/**
|
||||
* The name of the next node in the resulting JS
|
||||
*
|
||||
* Defaults to `#text`
|
||||
*/
|
||||
textNodeName?: string;
|
||||
|
||||
/**
|
||||
* Whether to ignore attributes when parsing
|
||||
*
|
||||
* When `true` - ignores all the attributes
|
||||
*
|
||||
* When `false` - parses all the attributes
|
||||
*
|
||||
* When `Array<string | RegExp>` - filters out attributes that match provided patterns
|
||||
*
|
||||
* When `Function` - calls the function for each attribute and filters out those for which the function returned `true`
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPath: string) => boolean);
|
||||
|
||||
/**
|
||||
* Whether to remove namespace string from tag and attribute names
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
removeNSPrefix?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to allow attributes without value
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
allowBooleanAttributes?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to parse tag value with `strnum` package
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
parseTagValue?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to parse tag value with `strnum` package
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
parseAttributeValue?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to remove surrounding whitespace from tag or attribute value
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
trimValues?: boolean;
|
||||
|
||||
/**
|
||||
* Give a property name to set CDATA values to instead of merging to tag's text value
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
cdataPropName?: false | string;
|
||||
|
||||
/**
|
||||
* If set, parse comments and set as this property
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
commentPropName?: false | string;
|
||||
|
||||
/**
|
||||
* Control how tag value should be parsed. Called only if tag value is not empty
|
||||
*
|
||||
* @returns {undefined|null} `undefined` or `null` to set original value.
|
||||
* @returns {unknown}
|
||||
*
|
||||
* 1. Different value or value with different data type to set new value.
|
||||
* 2. Same value to set parsed value if `parseTagValue: true`.
|
||||
*
|
||||
* Defaults to `(tagName, val, jPath, hasAttributes, isLeafNode) => val`
|
||||
*/
|
||||
tagValueProcessor?: (tagName: string, tagValue: string, jPath: string, hasAttributes: boolean, isLeafNode: boolean) => unknown;
|
||||
|
||||
/**
|
||||
* Control how attribute value should be parsed
|
||||
*
|
||||
* @param attrName
|
||||
* @param attrValue
|
||||
* @param jPath
|
||||
* @returns {undefined|null} `undefined` or `null` to set original value
|
||||
* @returns {unknown}
|
||||
*
|
||||
* Defaults to `(attrName, val, jPath) => val`
|
||||
*/
|
||||
attributeValueProcessor?: (attrName: string, attrValue: string, jPath: string) => unknown;
|
||||
|
||||
/**
|
||||
* Options to pass to `strnum` for parsing numbers
|
||||
*
|
||||
* Defaults to `{ hex: true, leadingZeros: true, eNotation: true }`
|
||||
*/
|
||||
numberParseOptions?: strnumOptions;
|
||||
|
||||
/**
|
||||
* Nodes to stop parsing at
|
||||
*
|
||||
* Defaults to `[]`
|
||||
*/
|
||||
stopNodes?: string[];
|
||||
|
||||
/**
|
||||
* List of tags without closing tags
|
||||
*
|
||||
* Defaults to `[]`
|
||||
*/
|
||||
unpairedTags?: string[];
|
||||
|
||||
/**
|
||||
* Whether to always create a text node
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
alwaysCreateTextNode?: boolean;
|
||||
|
||||
/**
|
||||
* Determine whether a tag should be parsed as an array
|
||||
*
|
||||
* @param tagName
|
||||
* @param jPath
|
||||
* @param isLeafNode
|
||||
* @param isAttribute
|
||||
* @returns {boolean}
|
||||
*
|
||||
* Defaults to `() => false`
|
||||
*/
|
||||
isArray?: (tagName: string, jPath: string, isLeafNode: boolean, isAttribute: boolean) => boolean;
|
||||
|
||||
/**
|
||||
* Whether to process default and DOCTYPE entities
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
processEntities?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to process HTML entities
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
htmlEntities?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to ignore the declaration tag from output
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
ignoreDeclaration?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to ignore Pi tags
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
ignorePiTags?: boolean;
|
||||
|
||||
/**
|
||||
* Transform tag names
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
transformTagName?: ((tagName: string) => string) | false;
|
||||
|
||||
/**
|
||||
* Transform attribute names
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
transformAttributeName?: ((attributeName: string) => string) | false;
|
||||
|
||||
/**
|
||||
* Change the tag name when a different name is returned. Skip the tag from parsed result when false is returned.
|
||||
* Modify `attrs` object to control attributes for the given tag.
|
||||
*
|
||||
* @returns {string} new tag name.
|
||||
* @returns false to skip the tag
|
||||
*
|
||||
* Defaults to `(tagName, jPath, attrs) => tagName`
|
||||
*/
|
||||
updateTag?: (tagName: string, jPath: string, attrs: {[k: string]: string}) => string | boolean;
|
||||
};
|
||||
|
||||
type strnumOptions = {
|
||||
hex: boolean;
|
||||
leadingZeros: boolean,
|
||||
skipLike?: RegExp,
|
||||
eNotation?: boolean
|
||||
}
|
||||
|
||||
type validationOptions = {
|
||||
/**
|
||||
* Whether to allow attributes without value
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
allowBooleanAttributes?: boolean;
|
||||
|
||||
/**
|
||||
* List of tags without closing tags
|
||||
*
|
||||
* Defaults to `[]`
|
||||
*/
|
||||
unpairedTags?: string[];
|
||||
};
|
||||
|
||||
type XmlBuilderOptions = {
|
||||
/**
|
||||
* Give a prefix to the attribute name in the resulting JS object
|
||||
*
|
||||
* Defaults to '@_'
|
||||
*/
|
||||
attributeNamePrefix?: string;
|
||||
|
||||
/**
|
||||
* A name to group all attributes of a tag under, or `false` to disable
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
attributesGroupName?: false | string;
|
||||
|
||||
/**
|
||||
* The name of the next node in the resulting JS
|
||||
*
|
||||
* Defaults to `#text`
|
||||
*/
|
||||
textNodeName?: string;
|
||||
|
||||
/**
|
||||
* Whether to ignore attributes when building
|
||||
*
|
||||
* When `true` - ignores all the attributes
|
||||
*
|
||||
* When `false` - builds all the attributes
|
||||
*
|
||||
* When `Array<string | RegExp>` - filters out attributes that match provided patterns
|
||||
*
|
||||
* When `Function` - calls the function for each attribute and filters out those for which the function returned `true`
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPath: string) => boolean);
|
||||
|
||||
/**
|
||||
* Give a property name to set CDATA values to instead of merging to tag's text value
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
cdataPropName?: false | string;
|
||||
|
||||
/**
|
||||
* If set, parse comments and set as this property
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
commentPropName?: false | string;
|
||||
|
||||
/**
|
||||
* Whether to make output pretty instead of single line
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
format?: boolean;
|
||||
|
||||
|
||||
/**
|
||||
* If `format` is set to `true`, sets the indent string
|
||||
*
|
||||
* Defaults to ` `
|
||||
*/
|
||||
indentBy?: string;
|
||||
|
||||
/**
|
||||
* Give a name to a top-level array
|
||||
*
|
||||
* Defaults to `undefined`
|
||||
*/
|
||||
arrayNodeName?: string;
|
||||
|
||||
/**
|
||||
* Create empty tags for tags with no text value
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
suppressEmptyNode?: boolean;
|
||||
|
||||
/**
|
||||
* Suppress an unpaired tag
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
suppressUnpairedNode?: boolean;
|
||||
|
||||
/**
|
||||
* Don't put a value for boolean attributes
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
suppressBooleanAttributes?: boolean;
|
||||
|
||||
/**
|
||||
* Preserve the order of tags in resulting JS object
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
preserveOrder?: boolean;
|
||||
|
||||
/**
|
||||
* List of tags without closing tags
|
||||
*
|
||||
* Defaults to `[]`
|
||||
*/
|
||||
unpairedTags?: string[];
|
||||
|
||||
/**
|
||||
* Nodes to stop parsing at
|
||||
*
|
||||
* Defaults to `[]`
|
||||
*/
|
||||
stopNodes?: string[];
|
||||
|
||||
/**
|
||||
* Control how tag value should be parsed. Called only if tag value is not empty
|
||||
*
|
||||
* @returns {undefined|null} `undefined` or `null` to set original value.
|
||||
* @returns {unknown}
|
||||
*
|
||||
* 1. Different value or value with different data type to set new value.
|
||||
* 2. Same value to set parsed value if `parseTagValue: true`.
|
||||
*
|
||||
* Defaults to `(tagName, val, jPath, hasAttributes, isLeafNode) => val`
|
||||
*/
|
||||
tagValueProcessor?: (name: string, value: unknown) => unknown;
|
||||
|
||||
/**
|
||||
* Control how attribute value should be parsed
|
||||
*
|
||||
* @param attrName
|
||||
* @param attrValue
|
||||
* @param jPath
|
||||
* @returns {undefined|null} `undefined` or `null` to set original value
|
||||
* @returns {unknown}
|
||||
*
|
||||
* Defaults to `(attrName, val, jPath) => val`
|
||||
*/
|
||||
attributeValueProcessor?: (name: string, value: unknown) => unknown;
|
||||
|
||||
/**
|
||||
* Whether to process default and DOCTYPE entities
|
||||
*
|
||||
* Defaults to `true`
|
||||
*/
|
||||
processEntities?: boolean;
|
||||
|
||||
|
||||
oneListGroup?: boolean;
|
||||
};
|
||||
|
||||
type ESchema = string | object | Array<string|object>;
|
||||
|
||||
type ValidationError = {
|
||||
err: {
|
||||
code: string;
|
||||
msg: string,
|
||||
line: number,
|
||||
col: number
|
||||
};
|
||||
};
|
||||
|
||||
export class XMLParser {
|
||||
constructor(options?: X2jOptions);
|
||||
parse(xmlData: string | Buffer ,validationOptions?: validationOptions | boolean): any;
|
||||
/**
|
||||
* Add Entity which is not by default supported by this library
|
||||
* @param entityIdentifier {string} Eg: 'ent' for &ent;
|
||||
* @param entityValue {string} Eg: '\r'
|
||||
*/
|
||||
addEntity(entityIdentifier: string, entityValue: string): void;
|
||||
}
|
||||
|
||||
export class XMLValidator{
|
||||
static validate( xmlData: string, options?: validationOptions): true | ValidationError;
|
||||
}
|
||||
export class XMLBuilder {
|
||||
constructor(options?: XmlBuilderOptions);
|
||||
build(jObj: any): any;
|
||||
}
|
11
em2rp/node_modules/fast-xml-parser/src/fxp.js
generated
vendored
Normal file
11
em2rp/node_modules/fast-xml-parser/src/fxp.js
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const validator = require('./validator');
|
||||
const XMLParser = require('./xmlparser/XMLParser');
|
||||
const XMLBuilder = require('./xmlbuilder/json2xml');
|
||||
|
||||
module.exports = {
|
||||
XMLParser: XMLParser,
|
||||
XMLValidator: validator,
|
||||
XMLBuilder: XMLBuilder
|
||||
}
|
20
em2rp/node_modules/fast-xml-parser/src/ignoreAttributes.js
generated
vendored
Normal file
20
em2rp/node_modules/fast-xml-parser/src/ignoreAttributes.js
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
function getIgnoreAttributesFn(ignoreAttributes) {
|
||||
if (typeof ignoreAttributes === 'function') {
|
||||
return ignoreAttributes
|
||||
}
|
||||
if (Array.isArray(ignoreAttributes)) {
|
||||
return (attrName) => {
|
||||
for (const pattern of ignoreAttributes) {
|
||||
if (typeof pattern === 'string' && attrName === pattern) {
|
||||
return true
|
||||
}
|
||||
if (pattern instanceof RegExp && pattern.test(attrName)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return () => false
|
||||
}
|
||||
|
||||
module.exports = getIgnoreAttributesFn
|
72
em2rp/node_modules/fast-xml-parser/src/util.js
generated
vendored
Normal file
72
em2rp/node_modules/fast-xml-parser/src/util.js
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
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';
|
||||
const nameChar = nameStartChar + '\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
|
||||
const nameRegexp = '[' + nameStartChar + '][' + nameChar + ']*'
|
||||
const regexName = new RegExp('^' + nameRegexp + '$');
|
||||
|
||||
const getAllMatches = function(string, regex) {
|
||||
const matches = [];
|
||||
let match = regex.exec(string);
|
||||
while (match) {
|
||||
const allmatches = [];
|
||||
allmatches.startIndex = regex.lastIndex - match[0].length;
|
||||
const len = match.length;
|
||||
for (let index = 0; index < len; index++) {
|
||||
allmatches.push(match[index]);
|
||||
}
|
||||
matches.push(allmatches);
|
||||
match = regex.exec(string);
|
||||
}
|
||||
return matches;
|
||||
};
|
||||
|
||||
const isName = function(string) {
|
||||
const match = regexName.exec(string);
|
||||
return !(match === null || typeof match === 'undefined');
|
||||
};
|
||||
|
||||
exports.isExist = function(v) {
|
||||
return typeof v !== 'undefined';
|
||||
};
|
||||
|
||||
exports.isEmptyObject = function(obj) {
|
||||
return Object.keys(obj).length === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy all the properties of a into b.
|
||||
* @param {*} target
|
||||
* @param {*} a
|
||||
*/
|
||||
exports.merge = function(target, a, arrayMode) {
|
||||
if (a) {
|
||||
const keys = Object.keys(a); // will return an array of own properties
|
||||
const len = keys.length; //don't make it inline
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (arrayMode === 'strict') {
|
||||
target[keys[i]] = [ a[keys[i]] ];
|
||||
} else {
|
||||
target[keys[i]] = a[keys[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
/* exports.merge =function (b,a){
|
||||
return Object.assign(b,a);
|
||||
} */
|
||||
|
||||
exports.getValue = function(v) {
|
||||
if (exports.isExist(v)) {
|
||||
return v;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
// const fakeCall = function(a) {return a;};
|
||||
// const fakeCallNoReturn = function() {};
|
||||
|
||||
exports.isName = isName;
|
||||
exports.getAllMatches = getAllMatches;
|
||||
exports.nameRegexp = nameRegexp;
|
16
em2rp/node_modules/fast-xml-parser/src/v5/CharsSymbol.js
generated
vendored
Normal file
16
em2rp/node_modules/fast-xml-parser/src/v5/CharsSymbol.js
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
modules.export = {
|
||||
"<" : "<", //tag start
|
||||
">" : ">", //tag end
|
||||
"/" : "/", //close tag
|
||||
"!" : "!", //comment or docttype
|
||||
"!--" : "!--", //comment
|
||||
"-->" : "-->", //comment end
|
||||
"?" : "?", //pi
|
||||
"?>" : "?>", //pi end
|
||||
"?xml" : "?xml", //pi end
|
||||
"![" : "![", //cdata
|
||||
"]]>" : "]]>", //cdata end
|
||||
"[" : "[",
|
||||
"-" : "-",
|
||||
"D" : "D",
|
||||
}
|
107
em2rp/node_modules/fast-xml-parser/src/v5/EntitiesParser.js
generated
vendored
Normal file
107
em2rp/node_modules/fast-xml-parser/src/v5/EntitiesParser.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
const ampEntity = { regex: /&(amp|#38|#x26);/g, val : "&"};
|
||||
const htmlEntities = {
|
||||
"space": { regex: /&(nbsp|#160);/g, val: " " },
|
||||
// "lt" : { regex: /&(lt|#60);/g, val: "<" },
|
||||
// "gt" : { regex: /&(gt|#62);/g, val: ">" },
|
||||
// "amp" : { regex: /&(amp|#38);/g, val: "&" },
|
||||
// "quot" : { regex: /&(quot|#34);/g, val: "\"" },
|
||||
// "apos" : { regex: /&(apos|#39);/g, val: "'" },
|
||||
"cent" : { regex: /&(cent|#162);/g, val: "¢" },
|
||||
"pound" : { regex: /&(pound|#163);/g, val: "£" },
|
||||
"yen" : { regex: /&(yen|#165);/g, val: "¥" },
|
||||
"euro" : { regex: /&(euro|#8364);/g, val: "€" },
|
||||
"copyright" : { regex: /&(copy|#169);/g, val: "©" },
|
||||
"reg" : { regex: /&(reg|#174);/g, val: "®" },
|
||||
"inr" : { regex: /&(inr|#8377);/g, val: "₹" },
|
||||
"num_dec": { regex: /&#([0-9]{1,7});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 10)) },
|
||||
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 16)) },
|
||||
};
|
||||
|
||||
class EntitiesParser{
|
||||
constructor(replaceHtmlEntities) {
|
||||
this.replaceHtmlEntities = replaceHtmlEntities;
|
||||
this.docTypeEntities = {};
|
||||
this.lastEntities = {
|
||||
"apos" : { regex: /&(apos|#39|#x27);/g, val : "'"},
|
||||
"gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"},
|
||||
"lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"},
|
||||
"quot" : { regex: /&(quot|#34|#x22);/g, val : "\""},
|
||||
};
|
||||
}
|
||||
|
||||
addExternalEntities(externalEntities){
|
||||
const entKeys = Object.keys(externalEntities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.addExternalEntity(ent,externalEntities[ent])
|
||||
}
|
||||
}
|
||||
addExternalEntity(key,val){
|
||||
validateEntityName(key);
|
||||
if(val.indexOf("&") !== -1) {
|
||||
reportWarning(`Entity ${key} is not added as '&' is found in value;`)
|
||||
return;
|
||||
}else{
|
||||
this.lastEntities[ent] = {
|
||||
regex: new RegExp("&"+key+";","g"),
|
||||
val : val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDocTypeEntities(entities){
|
||||
const entKeys = Object.keys(entities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.docTypeEntities[ent] = {
|
||||
regex: new RegExp("&"+ent+";","g"),
|
||||
val : entities[ent]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parse(val){
|
||||
return this.replaceEntitiesValue(val)
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Replace DOCTYPE entities
|
||||
* 2. Replace external entities
|
||||
* 3. Replace HTML entities if asked
|
||||
* @param {string} val
|
||||
*/
|
||||
replaceEntitiesValue(val){
|
||||
if(typeof val === "string" && val.length > 0){
|
||||
for(let entityName in this.docTypeEntities){
|
||||
const entity = this.docTypeEntities[entityName];
|
||||
val = val.replace( entity.regx, entity.val);
|
||||
}
|
||||
for(let entityName in this.lastEntities){
|
||||
const entity = this.lastEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
if(this.replaceHtmlEntities){
|
||||
for(let entityName in htmlEntities){
|
||||
const entity = htmlEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
val = val.replace( ampEntity.regex, ampEntity.val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
//an entity name should not contains special characters that may be used in regex
|
||||
//Eg !?\\\/[]$%{}^&*()<>
|
||||
const specialChar = "!?\\\/[]$%{}^&*()<>|+";
|
||||
|
||||
function validateEntityName(name){
|
||||
for (let i = 0; i < specialChar.length; i++) {
|
||||
const ch = specialChar[i];
|
||||
if(name.indexOf(ch) !== -1) throw new Error(`Invalid character ${ch} in entity name`);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
module.exports = EntitiesParser;
|
64
em2rp/node_modules/fast-xml-parser/src/v5/OptionsBuilder.js
generated
vendored
Normal file
64
em2rp/node_modules/fast-xml-parser/src/v5/OptionsBuilder.js
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
const JsObjOutputBuilder = require("./OutputBuilders/JsObjBuilder");
|
||||
|
||||
const defaultOptions = {
|
||||
preserveOrder: false,
|
||||
removeNSPrefix: false, // remove NS from tag name or attribute name if true
|
||||
//ignoreRootElement : false,
|
||||
stopNodes: [], //nested tags will not be parsed even for errors
|
||||
// isArray: () => false, //User will set it
|
||||
htmlEntities: false,
|
||||
// skipEmptyListItem: false
|
||||
tags:{
|
||||
unpaired: [],
|
||||
nameFor:{
|
||||
cdata: false,
|
||||
comment: false,
|
||||
text: '#text'
|
||||
},
|
||||
separateTextProperty: false,
|
||||
},
|
||||
attributes:{
|
||||
ignore: false,
|
||||
booleanType: true,
|
||||
entities: true,
|
||||
},
|
||||
|
||||
// select: ["img[src]"],
|
||||
// stop: ["anim", "[ads]"]
|
||||
only: [], // rest tags will be skipped. It will result in flat array
|
||||
hierarchy: false, //will be used when a particular tag is set to be parsed.
|
||||
skip: [], // will be skipped from parse result. on('skip') will be triggered
|
||||
|
||||
select: [], // on('select', tag => tag ) will be called if match
|
||||
stop: [], //given tagPath will not be parsed. innerXML will be set as string value
|
||||
OutputBuilder: new JsObjOutputBuilder(),
|
||||
};
|
||||
|
||||
const buildOptions = function(options) {
|
||||
const finalOptions = { ... defaultOptions};
|
||||
copyProperties(finalOptions,options)
|
||||
return finalOptions;
|
||||
};
|
||||
|
||||
function copyProperties(target, source) {
|
||||
for (let key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
if (key === 'OutputBuilder') {
|
||||
target[key] = source[key];
|
||||
}else if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
||||
// Recursively copy nested properties
|
||||
if (typeof target[key] === 'undefined') {
|
||||
target[key] = {};
|
||||
}
|
||||
copyProperties(target[key], source[key]);
|
||||
} else {
|
||||
// Copy non-nested properties
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.buildOptions = buildOptions;
|
||||
exports.defaultOptions = defaultOptions;
|
71
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/BaseOutputBuilder.js
generated
vendored
Normal file
71
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/BaseOutputBuilder.js
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
class BaseOutputBuilder{
|
||||
constructor(){
|
||||
// this.attributes = {};
|
||||
}
|
||||
|
||||
addAttribute(name, value){
|
||||
if(this.options.onAttribute){
|
||||
//TODO: better to pass tag path
|
||||
const v = this.options.onAttribute(name, value, this.tagName);
|
||||
if(v) this.attributes[v.name] = v.value;
|
||||
}else{
|
||||
name = this.options.attributes.prefix + name + this.options.attributes.suffix;
|
||||
this.attributes[name] = this.parseValue(value, this.options.attributes.valueParsers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse value by chain of parsers
|
||||
* @param {string} val
|
||||
* @returns {any} parsed value if matching parser found
|
||||
*/
|
||||
parseValue = function(val, valParsers){
|
||||
for (let i = 0; i < valParsers.length; i++) {
|
||||
let valParser = valParsers[i];
|
||||
if(typeof valParser === "string"){
|
||||
valParser = this.registeredParsers[valParser];
|
||||
}
|
||||
if(valParser){
|
||||
val = valParser.parse(val);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* To add a nested empty tag.
|
||||
* @param {string} key
|
||||
* @param {any} val
|
||||
*/
|
||||
_addChild(key, val){}
|
||||
|
||||
/**
|
||||
* skip the comment if property is not set
|
||||
*/
|
||||
addComment(text){
|
||||
if(this.options.nameFor.comment)
|
||||
this._addChild(this.options.nameFor.comment, text);
|
||||
}
|
||||
|
||||
//store CDATA separately if property is set
|
||||
//otherwise add to tag's value
|
||||
addCdata(text){
|
||||
if (this.options.nameFor.cdata) {
|
||||
this._addChild(this.options.nameFor.cdata, text);
|
||||
} else {
|
||||
this.addRawValue(text || "");
|
||||
}
|
||||
}
|
||||
|
||||
addRawValue = text => this.addValue(text);
|
||||
|
||||
addDeclaration(){
|
||||
if(!this.options.declaration){
|
||||
}else{
|
||||
this.addPi("?xml");
|
||||
}
|
||||
this.attributes = {}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BaseOutputBuilder;
|
103
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/JsArrBuilder.js
generated
vendored
Normal file
103
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/JsArrBuilder.js
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
const {buildOptions,registerCommonValueParsers} = require("./ParserOptionsBuilder");
|
||||
|
||||
class OutputBuilder{
|
||||
constructor(options){
|
||||
this.options = buildOptions(options);
|
||||
this.registeredParsers = registerCommonValueParsers(this.options);
|
||||
}
|
||||
|
||||
registerValueParser(name,parserInstance){//existing name will override the parser without warning
|
||||
this.registeredParsers[name] = parserInstance;
|
||||
}
|
||||
|
||||
getInstance(parserOptions){
|
||||
return new JsArrBuilder(parserOptions, this.options, this.registeredParsers);
|
||||
}
|
||||
}
|
||||
|
||||
const rootName = '!js_arr';
|
||||
const BaseOutputBuilder = require("./BaseOutputBuilder");
|
||||
|
||||
class JsArrBuilder extends BaseOutputBuilder{
|
||||
|
||||
constructor(parserOptions, options,registeredParsers) {
|
||||
super();
|
||||
this.tagsStack = [];
|
||||
this.parserOptions = parserOptions;
|
||||
this.options = options;
|
||||
this.registeredParsers = registeredParsers;
|
||||
|
||||
this.root = new Node(rootName);
|
||||
this.currentNode = this.root;
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
addTag(tag){
|
||||
//when a new tag is added, it should be added as child of current node
|
||||
//TODO: shift this check to the parser
|
||||
if(tag.name === "__proto__") tag.name = "#__proto__";
|
||||
|
||||
this.tagsStack.push(this.currentNode);
|
||||
this.currentNode = new Node(tag.name, this.attributes);
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node should be added by checking user's preference
|
||||
* @param {Node} node
|
||||
* @returns boolean: true if the node should not be added
|
||||
*/
|
||||
closeTag(){
|
||||
const node = this.currentNode;
|
||||
this.currentNode = this.tagsStack.pop(); //set parent node in scope
|
||||
if(this.options.onClose !== undefined){
|
||||
//TODO TagPathMatcher
|
||||
const resultTag = this.options.onClose(node,
|
||||
new TagPathMatcher(this.tagsStack,node));
|
||||
|
||||
if(resultTag) return;
|
||||
}
|
||||
this.currentNode.child.push(node); //to parent node
|
||||
}
|
||||
|
||||
//Called by parent class methods
|
||||
_addChild(key, val){
|
||||
// if(key === "__proto__") tagName = "#__proto__";
|
||||
this.currentNode.child.push( {[key]: val });
|
||||
// this.currentNode.leafType = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text value child node
|
||||
* @param {string} text
|
||||
*/
|
||||
addValue(text){
|
||||
this.currentNode.child.push( {[this.options.nameFor.text]: this.parseValue(text, this.options.tags.valueParsers) });
|
||||
}
|
||||
|
||||
addPi(name){
|
||||
//TODO: set pi flag
|
||||
if(!this.options.ignorePiTags){
|
||||
const node = new Node(name, this.attributes);
|
||||
this.currentNode[":@"] = this.attributes;
|
||||
this.currentNode.child.push(node);
|
||||
}
|
||||
this.attributes = {};
|
||||
}
|
||||
getOutput(){
|
||||
return this.root.child[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Node{
|
||||
constructor(tagname, attributes){
|
||||
this.tagname = tagname;
|
||||
this.child = []; //nested tags, text, cdata, comments
|
||||
if(attributes && Object.keys(attributes).length > 0)
|
||||
this[":@"] = attributes;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OutputBuilder;
|
102
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/JsMinArrBuilder.js
generated
vendored
Normal file
102
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/JsMinArrBuilder.js
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
const {buildOptions,registerCommonValueParsers} = require("./ParserOptionsBuilder");
|
||||
|
||||
class OutputBuilder{
|
||||
constructor(options){
|
||||
this.options = buildOptions(options);
|
||||
this.registeredParsers = registerCommonValueParsers(this.options);
|
||||
}
|
||||
|
||||
registerValueParser(name,parserInstance){//existing name will override the parser without warning
|
||||
this.registeredParsers[name] = parserInstance;
|
||||
}
|
||||
|
||||
getInstance(parserOptions){
|
||||
return new JsMinArrBuilder(parserOptions, this.options, this.registeredParsers);
|
||||
}
|
||||
}
|
||||
|
||||
const BaseOutputBuilder = require("./BaseOutputBuilder");
|
||||
const rootName = '^';
|
||||
|
||||
class JsMinArrBuilder extends BaseOutputBuilder{
|
||||
|
||||
constructor(parserOptions, options,registeredParsers) {
|
||||
super();
|
||||
this.tagsStack = [];
|
||||
this.parserOptions = parserOptions;
|
||||
this.options = options;
|
||||
this.registeredParsers = registeredParsers;
|
||||
|
||||
this.root = {[rootName]: []};
|
||||
this.currentNode = this.root;
|
||||
this.currentNodeTagName = rootName;
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
addTag(tag){
|
||||
//when a new tag is added, it should be added as child of current node
|
||||
//TODO: shift this check to the parser
|
||||
if(tag.name === "__proto__") tag.name = "#__proto__";
|
||||
|
||||
this.tagsStack.push([this.currentNodeTagName,this.currentNode]); //this.currentNode is parent node here
|
||||
this.currentNodeTagName = tag.name;
|
||||
this.currentNode = { [tag.name]:[]}
|
||||
if(Object.keys(this.attributes).length > 0){
|
||||
this.currentNode[":@"] = this.attributes;
|
||||
this.attributes = {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node should be added by checking user's preference
|
||||
* @param {Node} node
|
||||
* @returns boolean: true if the node should not be added
|
||||
*/
|
||||
closeTag(){
|
||||
const node = this.currentNode;
|
||||
const nodeName = this.currentNodeTagName;
|
||||
const arr = this.tagsStack.pop(); //set parent node in scope
|
||||
this.currentNodeTagName = arr[0];
|
||||
this.currentNode = arr[1];
|
||||
|
||||
if(this.options.onClose !== undefined){
|
||||
//TODO TagPathMatcher
|
||||
const resultTag = this.options.onClose(node,
|
||||
new TagPathMatcher(this.tagsStack,node));
|
||||
|
||||
if(resultTag) return;
|
||||
}
|
||||
this.currentNode[this.currentNodeTagName].push(node); //to parent node
|
||||
}
|
||||
|
||||
//Called by parent class methods
|
||||
_addChild(key, val){
|
||||
// if(key === "__proto__") tagName = "#__proto__";
|
||||
this.currentNode.push( {[key]: val });
|
||||
// this.currentNode.leafType = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text value child node
|
||||
* @param {string} text
|
||||
*/
|
||||
addValue(text){
|
||||
this.currentNode[this.currentNodeTagName].push( {[this.options.nameFor.text]: this.parseValue(text, this.options.tags.valueParsers) });
|
||||
}
|
||||
|
||||
addPi(name){
|
||||
if(!this.options.ignorePiTags){
|
||||
const node = { [name]:[]}
|
||||
if(this.attributes){
|
||||
node[":@"] = this.attributes;
|
||||
}
|
||||
this.currentNode.push(node);
|
||||
}
|
||||
this.attributes = {};
|
||||
}
|
||||
getOutput(){
|
||||
return this.root[rootName];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OutputBuilder;
|
156
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/JsObjBuilder.js
generated
vendored
Normal file
156
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/JsObjBuilder.js
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
|
||||
|
||||
const {buildOptions,registerCommonValueParsers} = require("./ParserOptionsBuilder");
|
||||
|
||||
class OutputBuilder{
|
||||
constructor(builderOptions){
|
||||
this.options = buildOptions(builderOptions);
|
||||
this.registeredParsers = registerCommonValueParsers(this.options);
|
||||
}
|
||||
|
||||
registerValueParser(name,parserInstance){//existing name will override the parser without warning
|
||||
this.registeredParsers[name] = parserInstance;
|
||||
}
|
||||
|
||||
getInstance(parserOptions){
|
||||
return new JsObjBuilder(parserOptions, this.options, this.registeredParsers);
|
||||
}
|
||||
}
|
||||
|
||||
const BaseOutputBuilder = require("./BaseOutputBuilder");
|
||||
const rootName = '^';
|
||||
|
||||
class JsObjBuilder extends BaseOutputBuilder{
|
||||
|
||||
constructor(parserOptions, builderOptions,registeredParsers) {
|
||||
super();
|
||||
//hold the raw detail of a tag and sequence with reference to the output
|
||||
this.tagsStack = [];
|
||||
this.parserOptions = parserOptions;
|
||||
this.options = builderOptions;
|
||||
this.registeredParsers = registeredParsers;
|
||||
|
||||
this.root = {};
|
||||
this.parent = this.root;
|
||||
this.tagName = rootName;
|
||||
this.value = {};
|
||||
this.textValue = "";
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
addTag(tag){
|
||||
|
||||
let value = "";
|
||||
if( !isEmpty(this.attributes)){
|
||||
value = {};
|
||||
if(this.options.attributes.groupBy){
|
||||
value[this.options.attributes.groupBy] = this.attributes;
|
||||
}else{
|
||||
value = this.attributes;
|
||||
}
|
||||
}
|
||||
|
||||
this.tagsStack.push([this.tagName, this.textValue, this.value]); //parent tag, parent text value, parent tag value (jsobj)
|
||||
this.tagName = tag.name;
|
||||
this.value = value;
|
||||
this.textValue = "";
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node should be added by checking user's preference
|
||||
* @param {Node} node
|
||||
* @returns boolean: true if the node should not be added
|
||||
*/
|
||||
closeTag(){
|
||||
const tagName = this.tagName;
|
||||
let value = this.value;
|
||||
let textValue = this.textValue;
|
||||
|
||||
//update tag text value
|
||||
if(typeof value !== "object" && !Array.isArray(value)){
|
||||
value = this.parseValue(textValue.trim(), this.options.tags.valueParsers);
|
||||
}else if(textValue.length > 0){
|
||||
value[this.options.nameFor.text] = this.parseValue(textValue.trim(), this.options.tags.valueParsers);
|
||||
}
|
||||
|
||||
|
||||
let resultTag= {
|
||||
tagName: tagName,
|
||||
value: value
|
||||
};
|
||||
|
||||
if(this.options.onTagClose !== undefined){
|
||||
//TODO TagPathMatcher
|
||||
resultTag = this.options.onClose(tagName, value, this.textValue, new TagPathMatcher(this.tagsStack,node));
|
||||
|
||||
if(!resultTag) return;
|
||||
}
|
||||
|
||||
//set parent node in scope
|
||||
let arr = this.tagsStack.pop();
|
||||
let parentTag = arr[2];
|
||||
parentTag=this._addChildTo(resultTag.tagName, resultTag.value, parentTag);
|
||||
|
||||
this.tagName = arr[0];
|
||||
this.textValue = arr[1];
|
||||
this.value = parentTag;
|
||||
}
|
||||
|
||||
_addChild(key, val){
|
||||
if(typeof this.value === "string"){
|
||||
this.value = { [this.options.nameFor.text] : this.value };
|
||||
}
|
||||
|
||||
this._addChildTo(key, val, this.value);
|
||||
// this.currentNode.leafType = false;
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
_addChildTo(key, val, node){
|
||||
if(typeof node === 'string') node = {};
|
||||
if(!node[key]){
|
||||
node[key] = val;
|
||||
}else{ //Repeated
|
||||
if(!Array.isArray(node[key])){ //but not stored as array
|
||||
node[key] = [node[key]];
|
||||
}
|
||||
node[key].push(val);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add text value child node
|
||||
* @param {string} text
|
||||
*/
|
||||
addValue(text){
|
||||
//TODO: use bytes join
|
||||
if(this.textValue.length > 0) this.textValue += " " + text;
|
||||
else this.textValue = text;
|
||||
}
|
||||
|
||||
addPi(name){
|
||||
let value = "";
|
||||
if( !isEmpty(this.attributes)){
|
||||
value = {};
|
||||
if(this.options.attributes.groupBy){
|
||||
value[this.options.attributes.groupBy] = this.attributes;
|
||||
}else{
|
||||
value = this.attributes;
|
||||
}
|
||||
}
|
||||
this._addChild(name, value);
|
||||
|
||||
}
|
||||
getOutput(){
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
function isEmpty(obj) {
|
||||
return Object.keys(obj).length === 0;
|
||||
}
|
||||
|
||||
module.exports = OutputBuilder;
|
99
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/ParserOptionsBuilder.js
generated
vendored
Normal file
99
em2rp/node_modules/fast-xml-parser/src/v5/OutputBuilders/ParserOptionsBuilder.js
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
const trimParser = require("../valueParsers/trim")
|
||||
const booleanParser = require("../valueParsers/booleanParser")
|
||||
const currencyParser = require("../valueParsers/currency")
|
||||
const numberParser = require("../valueParsers/number")
|
||||
|
||||
const defaultOptions={
|
||||
nameFor:{
|
||||
text: "#text",
|
||||
comment: "",
|
||||
cdata: "",
|
||||
},
|
||||
// onTagClose: () => {},
|
||||
// onAttribute: () => {},
|
||||
piTag: false,
|
||||
declaration: false, //"?xml"
|
||||
tags: {
|
||||
valueParsers: [
|
||||
// "trim",
|
||||
// "boolean",
|
||||
// "number",
|
||||
// "currency",
|
||||
// "date",
|
||||
]
|
||||
},
|
||||
attributes:{
|
||||
prefix: "@_",
|
||||
suffix: "",
|
||||
groupBy: "",
|
||||
|
||||
valueParsers: [
|
||||
// "trim",
|
||||
// "boolean",
|
||||
// "number",
|
||||
// "currency",
|
||||
// "date",
|
||||
]
|
||||
},
|
||||
dataType:{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
const withJoin = ["trim","join", /*"entities",*/"number","boolean","currency"/*, "date"*/]
|
||||
const withoutJoin = ["trim", /*"entities",*/"number","boolean","currency"/*, "date"*/]
|
||||
|
||||
function buildOptions(options){
|
||||
//clone
|
||||
const finalOptions = { ... defaultOptions};
|
||||
|
||||
//add config missed in cloning
|
||||
finalOptions.tags.valueParsers.push(...withJoin)
|
||||
if(!this.preserveOrder)
|
||||
finalOptions.tags.valueParsers.push(...withoutJoin);
|
||||
|
||||
//add config missed in cloning
|
||||
finalOptions.attributes.valueParsers.push(...withJoin)
|
||||
|
||||
//override configuration
|
||||
copyProperties(finalOptions,options);
|
||||
return finalOptions;
|
||||
}
|
||||
|
||||
function copyProperties(target, source) {
|
||||
for (let key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
||||
// Recursively copy nested properties
|
||||
if (typeof target[key] === 'undefined') {
|
||||
target[key] = {};
|
||||
}
|
||||
copyProperties(target[key], source[key]);
|
||||
} else {
|
||||
// Copy non-nested properties
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function registerCommonValueParsers(options){
|
||||
return {
|
||||
"trim": new trimParser(),
|
||||
// "join": this.entityParser.parse,
|
||||
"boolean": new booleanParser(),
|
||||
"number": new numberParser({
|
||||
hex: true,
|
||||
leadingZeros: true,
|
||||
eNotation: true
|
||||
}),
|
||||
"currency": new currencyParser(),
|
||||
// "date": this.entityParser.parse,
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildOptions : buildOptions,
|
||||
registerCommonValueParsers: registerCommonValueParsers
|
||||
}
|
0
em2rp/node_modules/fast-xml-parser/src/v5/Report.js
generated
vendored
Normal file
0
em2rp/node_modules/fast-xml-parser/src/v5/Report.js
generated
vendored
Normal file
81
em2rp/node_modules/fast-xml-parser/src/v5/TagPath.js
generated
vendored
Normal file
81
em2rp/node_modules/fast-xml-parser/src/v5/TagPath.js
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
class TagPath{
|
||||
constructor(pathStr){
|
||||
let text = "";
|
||||
let tName = "";
|
||||
let pos;
|
||||
let aName = "";
|
||||
let aVal = "";
|
||||
this.stack = []
|
||||
|
||||
for (let i = 0; i < pathStr.length; i++) {
|
||||
let ch = pathStr[i];
|
||||
if(ch === " ") {
|
||||
if(text.length === 0) continue;
|
||||
tName = text; text = "";
|
||||
}else if(ch === "["){
|
||||
if(tName.length === 0){
|
||||
tName = text; text = "";
|
||||
}
|
||||
i++;
|
||||
for (; i < pathStr.length; i++) {
|
||||
ch = pathStr[i];
|
||||
if(ch=== "=") continue;
|
||||
else if(ch=== "]") {aName = text.trim(); text=""; break; i--;}
|
||||
else if(ch === "'" || ch === '"'){
|
||||
let attrEnd = pathStr.indexOf(ch,i+1);
|
||||
aVal = pathStr.substring(i+1, attrEnd);
|
||||
i = attrEnd;
|
||||
}else{
|
||||
text +=ch;
|
||||
}
|
||||
}
|
||||
}else if(ch !== " " && text.length === 0 && tName.length > 0){//reading tagName
|
||||
//save previous tag
|
||||
this.stack.push(new TagPathNode(tName,pos,aName,aVal));
|
||||
text = ch; tName = ""; aName = ""; aVal = "";
|
||||
}else{
|
||||
text+=ch;
|
||||
}
|
||||
}
|
||||
|
||||
//last tag in the path
|
||||
if(tName.length >0 || text.length>0){
|
||||
this.stack.push(new TagPathNode(text||tName,pos,aName,aVal));
|
||||
}
|
||||
}
|
||||
|
||||
match(tagStack,node){
|
||||
if(this.stack[0].name !== "*"){
|
||||
if(this.stack.length !== tagStack.length +1) return false;
|
||||
|
||||
//loop through tagPath and tagStack and match
|
||||
for (let i = 0; i < this.tagStack.length; i++) {
|
||||
if(!this.stack[i].match(tagStack[i])) return false;
|
||||
}
|
||||
}
|
||||
if(!this.stack[this.stack.length - 1].match(node)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class TagPathNode{
|
||||
constructor(name,position,attrName,attrVal){
|
||||
this.name = name;
|
||||
this.position = position;
|
||||
this.attrName = attrName,
|
||||
this.attrVal = attrVal;
|
||||
}
|
||||
|
||||
match(node){
|
||||
let matching = true;
|
||||
matching = node.name === this.name;
|
||||
if(this.position) matching = node.position === this.position;
|
||||
if(this.attrName) matching = node.attrs[this.attrName !== undefined];
|
||||
if(this.attrVal) matching = node.attrs[this.attrName !== this.attrVal];
|
||||
return matching;
|
||||
}
|
||||
}
|
||||
|
||||
// console.log((new TagPath("* b[b]")).stack);
|
||||
// console.log((new TagPath("a[a] b[b] c")).stack);
|
||||
// console.log((new TagPath(" b [ b= 'cf sdadwa' ] a ")).stack);
|
15
em2rp/node_modules/fast-xml-parser/src/v5/TagPathMatcher.js
generated
vendored
Normal file
15
em2rp/node_modules/fast-xml-parser/src/v5/TagPathMatcher.js
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
const TagPath = require("./TagPath");
|
||||
|
||||
class TagPathMatcher{
|
||||
constructor(stack,node){
|
||||
this.stack = stack;
|
||||
this.node= node;
|
||||
}
|
||||
|
||||
match(path){
|
||||
const tagPath = new TagPath(path);
|
||||
return tagPath.match(this.stack, this.node);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TagPathMatcher;
|
85
em2rp/node_modules/fast-xml-parser/src/v5/XMLParser.js
generated
vendored
Normal file
85
em2rp/node_modules/fast-xml-parser/src/v5/XMLParser.js
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
const { buildOptions} = require("./OptionsBuilder");
|
||||
const Xml2JsParser = require("./Xml2JsParser");
|
||||
|
||||
class XMLParser{
|
||||
|
||||
constructor(options){
|
||||
this.externalEntities = {};
|
||||
this.options = buildOptions(options);
|
||||
// console.log(this.options)
|
||||
}
|
||||
/**
|
||||
* Parse XML data string to JS object
|
||||
* @param {string|Buffer} xmlData
|
||||
* @param {boolean|Object} validationOption
|
||||
*/
|
||||
parse(xmlData){
|
||||
if(Array.isArray(xmlData) && xmlData.byteLength !== undefined){
|
||||
return this.parse(xmlData);
|
||||
}else if( xmlData.toString){
|
||||
xmlData = xmlData.toString();
|
||||
}else{
|
||||
throw new Error("XML data is accepted in String or Bytes[] form.")
|
||||
}
|
||||
// if( validationOption){
|
||||
// if(validationOption === true) validationOption = {}; //validate with default options
|
||||
|
||||
// const result = validator.validate(xmlData, validationOption);
|
||||
// if (result !== true) {
|
||||
// throw Error( `${result.err.msg}:${result.err.line}:${result.err.col}` )
|
||||
// }
|
||||
// }
|
||||
const parser = new Xml2JsParser(this.options);
|
||||
parser.entityParser.addExternalEntities(this.externalEntities);
|
||||
return parser.parse(xmlData);
|
||||
}
|
||||
/**
|
||||
* Parse XML data buffer to JS object
|
||||
* @param {string|Buffer} xmlData
|
||||
* @param {boolean|Object} validationOption
|
||||
*/
|
||||
parseBytesArr(xmlData){
|
||||
if(Array.isArray(xmlData) && xmlData.byteLength !== undefined){
|
||||
}else{
|
||||
throw new Error("XML data is accepted in Bytes[] form.")
|
||||
}
|
||||
const parser = new Xml2JsParser(this.options);
|
||||
parser.entityParser.addExternalEntities(this.externalEntities);
|
||||
return parser.parseBytesArr(xmlData);
|
||||
}
|
||||
/**
|
||||
* Parse XML data stream to JS object
|
||||
* @param {fs.ReadableStream} xmlDataStream
|
||||
*/
|
||||
parseStream(xmlDataStream){
|
||||
if(!isStream(xmlDataStream)) throw new Error("FXP: Invalid stream input");
|
||||
|
||||
const orderedObjParser = new Xml2JsParser(this.options);
|
||||
orderedObjParser.entityParser.addExternalEntities(this.externalEntities);
|
||||
return orderedObjParser.parseStream(xmlDataStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Entity which is not by default supported by this library
|
||||
* @param {string} key
|
||||
* @param {string} value
|
||||
*/
|
||||
addEntity(key, value){
|
||||
if(value.indexOf("&") !== -1){
|
||||
throw new Error("Entity value can't have '&'")
|
||||
}else if(key.indexOf("&") !== -1 || key.indexOf(";") !== -1){
|
||||
throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '
'")
|
||||
}else if(value === "&"){
|
||||
throw new Error("An entity with value '&' is not permitted");
|
||||
}else{
|
||||
this.externalEntities[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isStream(stream){
|
||||
if(stream && typeof stream.read === "function" && typeof stream.on === "function" && typeof stream.readableEnded === "boolean") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = XMLParser;
|
237
em2rp/node_modules/fast-xml-parser/src/v5/Xml2JsParser.js
generated
vendored
Normal file
237
em2rp/node_modules/fast-xml-parser/src/v5/Xml2JsParser.js
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
const StringSource = require("./inputSource/StringSource");
|
||||
const BufferSource = require("./inputSource/BufferSource");
|
||||
const {readTagExp,readClosingTagName} = require("./XmlPartReader");
|
||||
const {readComment, readCdata,readDocType,readPiTag} = require("./XmlSpecialTagsReader");
|
||||
const TagPath = require("./TagPath");
|
||||
const TagPathMatcher = require("./TagPathMatcher");
|
||||
const EntitiesParser = require('./EntitiesParser');
|
||||
|
||||
//To hold the data of current tag
|
||||
//This is usually used to compare jpath expression against current tag
|
||||
class TagDetail{
|
||||
constructor(name){
|
||||
this.name = name;
|
||||
this.position = 0;
|
||||
// this.attributes = {};
|
||||
}
|
||||
}
|
||||
|
||||
class Xml2JsParser {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
|
||||
this.currentTagDetail = null;
|
||||
this.tagTextData = "";
|
||||
this.tagsStack = [];
|
||||
this.entityParser = new EntitiesParser(options.htmlEntities);
|
||||
this.stopNodes = [];
|
||||
for (let i = 0; i < this.options.stopNodes.length; i++) {
|
||||
this.stopNodes.push(new TagPath(this.options.stopNodes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
parse(strData) {
|
||||
this.source = new StringSource(strData);
|
||||
this.parseXml();
|
||||
return this.outputBuilder.getOutput();
|
||||
}
|
||||
parseBytesArr(data) {
|
||||
this.source = new BufferSource(data );
|
||||
this.parseXml();
|
||||
return this.outputBuilder.getOutput();
|
||||
}
|
||||
|
||||
parseXml() {
|
||||
//TODO: Separate TagValueParser as separate class. So no scope issue in node builder class
|
||||
|
||||
//OutputBuilder should be set in XML Parser
|
||||
this.outputBuilder = this.options.OutputBuilder.getInstance(this.options);
|
||||
this.root = { root: true};
|
||||
this.currentTagDetail = this.root;
|
||||
|
||||
while(this.source.canRead()){
|
||||
let ch = this.source.readCh();
|
||||
if (ch === "") break;
|
||||
|
||||
if(ch === "<"){//tagStart
|
||||
let nextChar = this.source.readChAt(0);
|
||||
if (nextChar === "" ) throw new Error("Unexpected end of source");
|
||||
|
||||
|
||||
if(nextChar === "!" || nextChar === "?"){
|
||||
this.source.updateBufferBoundary();
|
||||
//previously collected text should be added to current node
|
||||
this.addTextNode();
|
||||
|
||||
this.readSpecialTag(nextChar);// Read DOCTYPE, comment, CDATA, PI tag
|
||||
}else if(nextChar === "/"){
|
||||
this.source.updateBufferBoundary();
|
||||
this.readClosingTag();
|
||||
// console.log(this.source.buffer.length, this.source.readable);
|
||||
// console.log(this.tagsStack.length);
|
||||
}else{//opening tag
|
||||
this.readOpeningTag();
|
||||
}
|
||||
}else{
|
||||
this.tagTextData += ch;
|
||||
}
|
||||
}//End While loop
|
||||
if(this.tagsStack.length > 0 || ( this.tagTextData !== "undefined" && this.tagTextData.trimEnd().length > 0) ) throw new Error("Unexpected data in the end of document");
|
||||
}
|
||||
|
||||
/**
|
||||
* read closing paired tag. Set parent tag in scope.
|
||||
* skip a node on user's choice
|
||||
*/
|
||||
readClosingTag(){
|
||||
const tagName = this.processTagName(readClosingTagName(this.source));
|
||||
// console.log(tagName, this.tagsStack.length);
|
||||
this.validateClosingTag(tagName);
|
||||
// All the text data collected, belongs to current tag.
|
||||
if(!this.currentTagDetail.root) this.addTextNode();
|
||||
this.outputBuilder.closeTag();
|
||||
// Since the tag is closed now, parent tag comes in scope
|
||||
this.currentTagDetail = this.tagsStack.pop();
|
||||
}
|
||||
|
||||
validateClosingTag(tagName){
|
||||
// This can't be unpaired tag, or a stop tag.
|
||||
if(this.isUnpaired(tagName) || this.isStopNode(tagName)) throw new Error(`Unexpected closing tag '${tagName}'`);
|
||||
// This must match with last opening tag
|
||||
else if(tagName !== this.currentTagDetail.name)
|
||||
throw new Error(`Unexpected closing tag '${tagName}' expecting '${this.currentTagDetail.name}'`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Read paired, unpaired, self-closing, stop and special tags.
|
||||
* Create a new node
|
||||
* Push paired tag in stack.
|
||||
*/
|
||||
readOpeningTag(){
|
||||
//save previously collected text data to current node
|
||||
this.addTextNode();
|
||||
|
||||
//create new tag
|
||||
let tagExp = readTagExp(this, ">" );
|
||||
|
||||
// process and skip from tagsStack For unpaired tag, self closing tag, and stop node
|
||||
const tagDetail = new TagDetail(tagExp.tagName);
|
||||
if(this.isUnpaired(tagExp.tagName)) {
|
||||
//TODO: this will lead 2 extra stack operation
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.outputBuilder.closeTag();
|
||||
} else if(tagExp.selfClosing){
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.outputBuilder.closeTag();
|
||||
} else if(this.isStopNode(this.currentTagDetail)){
|
||||
// TODO: let's user set a stop node boundary detector for complex contents like script tag
|
||||
//TODO: pass tag name only to avoid string operations
|
||||
const content = source.readUptoCloseTag(`</${tagExp.tagName}`);
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.outputBuilder.addValue(content);
|
||||
this.outputBuilder.closeTag();
|
||||
}else{//paired tag
|
||||
//set new nested tag in scope.
|
||||
this.tagsStack.push(this.currentTagDetail);
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.currentTagDetail = tagDetail;
|
||||
}
|
||||
// console.log(tagExp.tagName,this.tagsStack.length);
|
||||
// this.options.onClose()
|
||||
|
||||
}
|
||||
|
||||
readSpecialTag(startCh){
|
||||
if(startCh == "!"){
|
||||
let nextChar = this.source.readCh();
|
||||
if (nextChar === null || nextChar === undefined) throw new Error("Unexpected ending of the source");
|
||||
|
||||
if(nextChar === "-"){//comment
|
||||
readComment(this);
|
||||
}else if(nextChar === "["){//CDATA
|
||||
readCdata(this);
|
||||
}else if(nextChar === "D"){//DOCTYPE
|
||||
readDocType(this);
|
||||
}
|
||||
}else if(startCh === "?"){
|
||||
readPiTag(this);
|
||||
}else{
|
||||
throw new Error(`Invalid tag '<${startCh}' at ${this.source.line}:${this.source.col}`)
|
||||
}
|
||||
}
|
||||
addTextNode = function() {
|
||||
// if(this.currentTagDetail){
|
||||
//save text as child node
|
||||
// if(this.currentTagDetail.tagname !== '!xml')
|
||||
if (this.tagTextData !== undefined && this.tagTextData !== "") { //store previously collected data as textNode
|
||||
if(this.tagTextData.trim().length > 0){
|
||||
//TODO: shift parsing to output builder
|
||||
|
||||
this.outputBuilder.addValue(this.replaceEntities(this.tagTextData));
|
||||
}
|
||||
this.tagTextData = "";
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
processAttrName(name){
|
||||
if(name === "__proto__") name = "#__proto__";
|
||||
name = resolveNameSpace(name, this.removeNSPrefix);
|
||||
return name;
|
||||
}
|
||||
|
||||
processTagName(name){
|
||||
if(name === "__proto__") name = "#__proto__";
|
||||
name = resolveNameSpace(name, this.removeNSPrefix);
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate tags path from tagsStack
|
||||
*/
|
||||
tagsPath(tagName){
|
||||
//TODO: return TagPath Object. User can call match method with path
|
||||
return "";
|
||||
}
|
||||
|
||||
isUnpaired(tagName){
|
||||
return this.options.tags.unpaired.indexOf(tagName) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* valid expressions are
|
||||
* tag nested
|
||||
* * nested
|
||||
* tag nested[attribute]
|
||||
* tag nested[attribute=""]
|
||||
* tag nested[attribute!=""]
|
||||
* tag nested:0 //for future
|
||||
* @param {string} tagName
|
||||
* @returns
|
||||
*/
|
||||
isStopNode(node){
|
||||
for (let i = 0; i < this.stopNodes.length; i++) {
|
||||
const givenPath = this.stopNodes[i];
|
||||
if(givenPath.match(this.tagsStack, node)) return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
replaceEntities(text){
|
||||
//TODO: if option is set then replace entities
|
||||
return this.entityParser.parse(text)
|
||||
}
|
||||
}
|
||||
|
||||
function resolveNameSpace(name, removeNSPrefix) {
|
||||
if (removeNSPrefix) {
|
||||
const parts = name.split(':');
|
||||
if(parts.length === 2){
|
||||
if (parts[0] === 'xmlns') return '';
|
||||
else return parts[1];
|
||||
}else reportError(`Multiple namespaces ${name}`)
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
module.exports = Xml2JsParser;
|
216
em2rp/node_modules/fast-xml-parser/src/v5/XmlPartReader.js
generated
vendored
Normal file
216
em2rp/node_modules/fast-xml-parser/src/v5/XmlPartReader.js
generated
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* find paired tag for a stop node
|
||||
* @param {string} xmlDoc
|
||||
* @param {string} tagName
|
||||
* @param {number} i : start index
|
||||
*/
|
||||
function readStopNode(xmlDoc, tagName, i){
|
||||
const startIndex = i;
|
||||
// Starting at 1 since we already have an open tag
|
||||
let openTagCount = 1;
|
||||
|
||||
for (; i < xmlDoc.length; i++) {
|
||||
if( xmlDoc[i] === "<"){
|
||||
if (xmlDoc[i+1] === "/") {//close tag
|
||||
const closeIndex = findSubStrIndex(xmlDoc, ">", i, `${tagName} is not closed`);
|
||||
let closeTagName = xmlDoc.substring(i+2,closeIndex).trim();
|
||||
if(closeTagName === tagName){
|
||||
openTagCount--;
|
||||
if (openTagCount === 0) {
|
||||
return {
|
||||
tagContent: xmlDoc.substring(startIndex, i),
|
||||
i : closeIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
i=closeIndex;
|
||||
} else if(xmlDoc[i+1] === '?') {
|
||||
const closeIndex = findSubStrIndex(xmlDoc, "?>", i+1, "StopNode is not closed.")
|
||||
i=closeIndex;
|
||||
} else if(xmlDoc.substr(i + 1, 3) === '!--') {
|
||||
const closeIndex = findSubStrIndex(xmlDoc, "-->", i+3, "StopNode is not closed.")
|
||||
i=closeIndex;
|
||||
} else if(xmlDoc.substr(i + 1, 2) === '![') {
|
||||
const closeIndex = findSubStrIndex(xmlDoc, "]]>", i, "StopNode is not closed.") - 2;
|
||||
i=closeIndex;
|
||||
} else {
|
||||
const tagData = readTagExp(xmlDoc, i, '>')
|
||||
|
||||
if (tagData) {
|
||||
const openTagName = tagData && tagData.tagName;
|
||||
if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length-1] !== "/") {
|
||||
openTagCount++;
|
||||
}
|
||||
i=tagData.closeIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}//end for loop
|
||||
}
|
||||
|
||||
/**
|
||||
* Read closing tag name
|
||||
* @param {Source} source
|
||||
* @returns tag name
|
||||
*/
|
||||
function readClosingTagName(source){
|
||||
let text = ""; //temporary data
|
||||
while(source.canRead()){
|
||||
let ch = source.readCh();
|
||||
// if (ch === null || ch === undefined) break;
|
||||
// source.updateBuffer();
|
||||
|
||||
if (ch === ">") return text.trimEnd();
|
||||
else text += ch;
|
||||
}
|
||||
throw new Error(`Unexpected end of source. Reading '${substr}'`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read XML tag and build attributes map
|
||||
* This function can be used to read normal tag, pi tag.
|
||||
* This function can't be used to read comment, CDATA, DOCTYPE.
|
||||
* Eg <tag attr = ' some"' attr= ">" bool>
|
||||
* @param {string} xmlDoc
|
||||
* @param {number} startIndex starting index
|
||||
* @returns tag expression includes tag name & attribute string
|
||||
*/
|
||||
function readTagExp(parser) {
|
||||
let inSingleQuotes = false;
|
||||
let inDoubleQuotes = false;
|
||||
let i;
|
||||
let EOE = false;
|
||||
|
||||
for (i = 0; parser.source.canRead(i); i++) {
|
||||
const char = parser.source.readChAt(i);
|
||||
|
||||
if (char === "'" && !inDoubleQuotes) {
|
||||
inSingleQuotes = !inSingleQuotes;
|
||||
} else if (char === '"' && !inSingleQuotes) {
|
||||
inDoubleQuotes = !inDoubleQuotes;
|
||||
} else if (char === '>' && !inSingleQuotes && !inDoubleQuotes) {
|
||||
// If not inside quotes, stop reading at '>'
|
||||
EOE = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if(inSingleQuotes || inDoubleQuotes){
|
||||
throw new Error("Invalid attribute expression. Quote is not properly closed");
|
||||
}else if(!EOE) throw new Error("Unexpected closing of source. Waiting for '>'");
|
||||
|
||||
|
||||
const exp = parser.source.readStr(i);
|
||||
parser.source.updateBufferBoundary(i + 1);
|
||||
return buildTagExpObj(exp, parser)
|
||||
}
|
||||
|
||||
function readPiExp(parser) {
|
||||
let inSingleQuotes = false;
|
||||
let inDoubleQuotes = false;
|
||||
let i;
|
||||
let EOE = false;
|
||||
|
||||
for (i = 0; parser.source.canRead(i) ; i++) {
|
||||
const currentChar = parser.source.readChAt(i);
|
||||
const nextChar = parser.source.readChAt(i+1);
|
||||
|
||||
if (currentChar === "'" && !inDoubleQuotes) {
|
||||
inSingleQuotes = !inSingleQuotes;
|
||||
} else if (currentChar === '"' && !inSingleQuotes) {
|
||||
inDoubleQuotes = !inDoubleQuotes;
|
||||
}
|
||||
|
||||
if (!inSingleQuotes && !inDoubleQuotes) {
|
||||
if (currentChar === '?' && nextChar === '>') {
|
||||
EOE = true;
|
||||
break; // Exit the loop when '?>' is found
|
||||
}
|
||||
}
|
||||
}
|
||||
if(inSingleQuotes || inDoubleQuotes){
|
||||
throw new Error("Invalid attribute expression. Quote is not properly closed in PI tag expression");
|
||||
}else if(!EOE) throw new Error("Unexpected closing of source. Waiting for '?>'");
|
||||
|
||||
if(!parser.options.attributes.ignore){
|
||||
//TODO: use regex to verify attributes if not set to ignore
|
||||
}
|
||||
|
||||
const exp = parser.source.readStr(i);
|
||||
parser.source.updateBufferBoundary(i + 1);
|
||||
return buildTagExpObj(exp, parser)
|
||||
}
|
||||
|
||||
function buildTagExpObj(exp, parser){
|
||||
const tagExp = {
|
||||
tagName: "",
|
||||
selfClosing: false
|
||||
};
|
||||
let attrsExp = "";
|
||||
|
||||
// Check for self-closing tag before setting the name
|
||||
if(exp[exp.length -1] === "/") {
|
||||
tagExp.selfClosing = true;
|
||||
exp = exp.slice(0, -1); // Remove the trailing slash
|
||||
}
|
||||
|
||||
//separate tag name
|
||||
let i = 0;
|
||||
for (; i < exp.length; i++) {
|
||||
const char = exp[i];
|
||||
if(char === " "){
|
||||
tagExp.tagName = exp.substring(0, i);
|
||||
attrsExp = exp.substring(i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//only tag
|
||||
if(tagExp.tagName.length === 0 && i === exp.length)tagExp.tagName = exp;
|
||||
|
||||
tagExp.tagName = tagExp.tagName.trimEnd();
|
||||
|
||||
if(!parser.options.attributes.ignore && attrsExp.length > 0){
|
||||
parseAttributesExp(attrsExp,parser)
|
||||
}
|
||||
|
||||
return tagExp;
|
||||
}
|
||||
|
||||
const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm');
|
||||
|
||||
function parseAttributesExp(attrStr, parser) {
|
||||
const matches = getAllMatches(attrStr, attrsRegx);
|
||||
const len = matches.length; //don't make it inline
|
||||
for (let i = 0; i < len; i++) {
|
||||
let attrName = parser.processAttrName(matches[i][1]);
|
||||
let attrVal = parser.replaceEntities(matches[i][4] || true);
|
||||
|
||||
parser.outputBuilder.addAttribute(attrName, attrVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const getAllMatches = function(string, regex) {
|
||||
const matches = [];
|
||||
let match = regex.exec(string);
|
||||
while (match) {
|
||||
const allmatches = [];
|
||||
allmatches.startIndex = regex.lastIndex - match[0].length;
|
||||
const len = match.length;
|
||||
for (let index = 0; index < len; index++) {
|
||||
allmatches.push(match[index]);
|
||||
}
|
||||
matches.push(allmatches);
|
||||
match = regex.exec(string);
|
||||
}
|
||||
return matches;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
readStopNode: readStopNode,
|
||||
readClosingTagName: readClosingTagName,
|
||||
readTagExp: readTagExp,
|
||||
readPiExp: readPiExp,
|
||||
}
|
118
em2rp/node_modules/fast-xml-parser/src/v5/XmlSpecialTagsReader.js
generated
vendored
Normal file
118
em2rp/node_modules/fast-xml-parser/src/v5/XmlSpecialTagsReader.js
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
const {readPiExp} = require("./XmlPartReader");
|
||||
|
||||
function readCdata(parser){
|
||||
//<![ are already read till this point
|
||||
let str = parser.source.readStr(6); //CDATA[
|
||||
parser.source.updateBufferBoundary(6);
|
||||
|
||||
if(str !== "CDATA[") throw new Error(`Invalid CDATA expression at ${parser.source.line}:${parser.source.cols}`);
|
||||
|
||||
let text = parser.source.readUpto("]]>");
|
||||
parser.outputBuilder.addCdata(text);
|
||||
}
|
||||
function readPiTag(parser){
|
||||
//<? are already read till this point
|
||||
let tagExp = readPiExp(parser, "?>");
|
||||
if(!tagExp) throw new Error("Invalid Pi Tag expression.");
|
||||
|
||||
if (tagExp.tagName === "?xml") {//TODO: test if tagName is just xml
|
||||
parser.outputBuilder.addDeclaration();
|
||||
} else {
|
||||
parser.outputBuilder.addPi("?"+tagExp.tagName);
|
||||
}
|
||||
}
|
||||
|
||||
function readComment(parser){
|
||||
//<!- are already read till this point
|
||||
let ch = parser.source.readCh();
|
||||
if(ch !== "-") throw new Error(`Invalid comment expression at ${parser.source.line}:${parser.source.cols}`);
|
||||
|
||||
let text = parser.source.readUpto("-->");
|
||||
parser.outputBuilder.addComment(text);
|
||||
}
|
||||
|
||||
const DOCTYPE_tags = {
|
||||
"EL":/^EMENT\s+([^\s>]+)\s+(ANY|EMPTY|\(.+\)\s*$)/m,
|
||||
"AT":/^TLIST\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+$/m,
|
||||
"NO":/^TATION.+$/m
|
||||
}
|
||||
function readDocType(parser){
|
||||
//<!D are already read till this point
|
||||
let str = parser.source.readStr(6); //OCTYPE
|
||||
parser.source.updateBufferBoundary(6);
|
||||
|
||||
if(str !== "OCTYPE") throw new Error(`Invalid DOCTYPE expression at ${parser.source.line}:${parser.source.cols}`);
|
||||
|
||||
let hasBody = false, lastch = "";
|
||||
|
||||
while(parser.source.canRead()){
|
||||
//TODO: use readChAt like used in partReader
|
||||
let ch = parser.source.readCh();
|
||||
if(hasBody){
|
||||
if (ch === '<') { //Determine the tag type
|
||||
let str = parser.source.readStr(2);
|
||||
parser.source.updateBufferBoundary(2);
|
||||
if(str === "EN"){ //ENTITY
|
||||
let str = parser.source.readStr(4);
|
||||
parser.source.updateBufferBoundary(4);
|
||||
if(str !== "TITY") throw new Error("Invalid DOCTYPE ENTITY expression");
|
||||
|
||||
registerEntity(parser);
|
||||
}else if(str === "!-") {//comment
|
||||
readComment(parser);
|
||||
}else{ //ELEMENT, ATTLIST, NOTATION
|
||||
let dTagExp = parser.source.readUpto(">");
|
||||
const regx = DOCTYPE_tags[str];
|
||||
if(regx){
|
||||
const match = dTagExp.match(regx);
|
||||
if(!match) throw new Error("Invalid DOCTYPE");
|
||||
}else throw new Error("Invalid DOCTYPE");
|
||||
}
|
||||
}else if( ch === '>' && lastch === "]"){//end of doctype
|
||||
return;
|
||||
}
|
||||
}else if( ch === '>'){//end of doctype
|
||||
return;
|
||||
}else if( ch === '['){
|
||||
hasBody = true;
|
||||
}else{
|
||||
lastch = ch;
|
||||
}
|
||||
}//End While loop
|
||||
|
||||
}
|
||||
|
||||
function registerEntity(parser){
|
||||
//read Entity
|
||||
let attrBoundary="";
|
||||
let name ="", val ="";
|
||||
while(source.canRead()){
|
||||
let ch = source.readCh();
|
||||
|
||||
if(attrBoundary){
|
||||
if (ch === attrBoundary){
|
||||
val = text;
|
||||
text = ""
|
||||
}
|
||||
}else if(ch === " " || ch === "\t"){
|
||||
if(!name){
|
||||
name = text.trimStart();
|
||||
text = "";
|
||||
}
|
||||
}else if (ch === '"' || ch === "'") {//start of attrBoundary
|
||||
attrBoundary = ch;
|
||||
}else if(ch === ">"){
|
||||
parser.entityParser.addExternalEntity(name,val);
|
||||
return;
|
||||
}else{
|
||||
text+=ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
readCdata: readCdata,
|
||||
readComment:readComment,
|
||||
readDocType:readDocType,
|
||||
readPiTag:readPiTag
|
||||
}
|
118
em2rp/node_modules/fast-xml-parser/src/v5/inputSource/BufferSource.js
generated
vendored
Normal file
118
em2rp/node_modules/fast-xml-parser/src/v5/inputSource/BufferSource.js
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
const Constants = {
|
||||
space: 32,
|
||||
tab: 9
|
||||
}
|
||||
class BufferSource{
|
||||
constructor(bytesArr){
|
||||
this.line = 1;
|
||||
this.cols = 0;
|
||||
this.buffer = bytesArr;
|
||||
this.startIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
readCh() {
|
||||
return String.fromCharCode(this.buffer[this.startIndex++]);
|
||||
}
|
||||
|
||||
readChAt(index) {
|
||||
return String.fromCharCode(this.buffer[this.startIndex+index]);
|
||||
}
|
||||
|
||||
readStr(n,from){
|
||||
if(typeof from === "undefined") from = this.startIndex;
|
||||
return this.buffer.slice(from, from + n).toString();
|
||||
}
|
||||
|
||||
readUpto(stopStr) {
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
const stopBuffer = Buffer.from(stopStr);
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
let match = true;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopBuffer[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
const result = this.buffer.slice(this.startIndex, i).toString();
|
||||
this.startIndex = i + stopLength;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readUptoCloseTag(stopStr) { //stopStr: "</tagname"
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
const stopBuffer = Buffer.from(stopStr);
|
||||
let stopIndex = 0;
|
||||
//0: non-matching, 1: matching stop string, 2: matching closing
|
||||
let match = 0;
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
if(match === 1){//initial part matched
|
||||
if(stopIndex === 0) stopIndex = i;
|
||||
if(this.buffer[i] === Constants.space || this.buffer[i] === Constants.tab) continue;
|
||||
else if(this.buffer[i] === '>'){ //TODO: if it should be equivalent ASCII
|
||||
match = 2;
|
||||
//tag boundary found
|
||||
// this.startIndex
|
||||
}
|
||||
}else{
|
||||
match = 1;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopBuffer[j]) {
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match === 2) {//matched closing part
|
||||
const result = this.buffer.slice(this.startIndex, stopIndex - 1 ).toString();
|
||||
this.startIndex = i + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readFromBuffer(n, shouldUpdate) {
|
||||
let ch;
|
||||
if (n === 1) {
|
||||
ch = this.buffer[this.startIndex];
|
||||
if (ch === 10) {
|
||||
this.line++;
|
||||
this.cols = 1;
|
||||
} else {
|
||||
this.cols++;
|
||||
}
|
||||
ch = String.fromCharCode(ch);
|
||||
} else {
|
||||
this.cols += n;
|
||||
ch = this.buffer.slice(this.startIndex, this.startIndex + n).toString();
|
||||
}
|
||||
if (shouldUpdate) this.updateBuffer(n);
|
||||
return ch;
|
||||
}
|
||||
|
||||
updateBufferBoundary(n = 1) { //n: number of characters read
|
||||
this.startIndex += n;
|
||||
}
|
||||
|
||||
canRead(n){
|
||||
n = n || this.startIndex;
|
||||
return this.buffer.length - n + 1 > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BufferSource;
|
123
em2rp/node_modules/fast-xml-parser/src/v5/inputSource/StringSource.js
generated
vendored
Normal file
123
em2rp/node_modules/fast-xml-parser/src/v5/inputSource/StringSource.js
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
const whiteSpaces = [" ", "\n", "\t"];
|
||||
|
||||
|
||||
class StringSource{
|
||||
constructor(str){
|
||||
this.line = 1;
|
||||
this.cols = 0;
|
||||
this.buffer = str;
|
||||
//a boundary pointer to indicate where from the buffer dat should be read
|
||||
// data before this pointer can be deleted to free the memory
|
||||
this.startIndex = 0;
|
||||
}
|
||||
|
||||
readCh() {
|
||||
return this.buffer[this.startIndex++];
|
||||
}
|
||||
|
||||
readChAt(index) {
|
||||
return this.buffer[this.startIndex+index];
|
||||
}
|
||||
|
||||
readStr(n,from){
|
||||
if(typeof from === "undefined") from = this.startIndex;
|
||||
return this.buffer.substring(from, from + n);
|
||||
}
|
||||
|
||||
readUpto(stopStr) {
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
let match = true;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopStr[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
const result = this.buffer.substring(this.startIndex, i);
|
||||
this.startIndex = i + stopLength;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readUptoCloseTag(stopStr) { //stopStr: "</tagname"
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
let stopIndex = 0;
|
||||
//0: non-matching, 1: matching stop string, 2: matching closing
|
||||
let match = 0;
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
if(match === 1){//initial part matched
|
||||
if(stopIndex === 0) stopIndex = i;
|
||||
if(this.buffer[i] === ' ' || this.buffer[i] === '\t') continue;
|
||||
else if(this.buffer[i] === '>'){
|
||||
match = 2;
|
||||
//tag boundary found
|
||||
// this.startIndex
|
||||
}
|
||||
}else{
|
||||
match = 1;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopStr[j]) {
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match === 2) {//matched closing part
|
||||
const result = this.buffer.substring(this.startIndex, stopIndex - 1 );
|
||||
this.startIndex = i + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readFromBuffer(n, updateIndex){
|
||||
let ch;
|
||||
if(n===1){
|
||||
ch = this.buffer[this.startIndex];
|
||||
// if(ch === "\n") {
|
||||
// this.line++;
|
||||
// this.cols = 1;
|
||||
// }else{
|
||||
// this.cols++;
|
||||
// }
|
||||
}else{
|
||||
ch = this.buffer.substring(this.startIndex, this.startIndex + n);
|
||||
// if("".indexOf("\n") !== -1){
|
||||
// //TODO: handle the scenario when there are multiple lines
|
||||
// //TODO: col should be set to number of chars after last '\n'
|
||||
// // this.cols = 1;
|
||||
// }else{
|
||||
// this.cols += n;
|
||||
|
||||
// }
|
||||
}
|
||||
if(updateIndex) this.updateBufferBoundary(n);
|
||||
return ch;
|
||||
}
|
||||
|
||||
//TODO: rename to updateBufferReadIndex
|
||||
|
||||
updateBufferBoundary(n = 1) { //n: number of characters read
|
||||
this.startIndex += n;
|
||||
}
|
||||
|
||||
canRead(n){
|
||||
n = n || this.startIndex;
|
||||
return this.buffer.length - n + 1 > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = StringSource;
|
107
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/EntitiesParser.js
generated
vendored
Normal file
107
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/EntitiesParser.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
const ampEntity = { regex: /&(amp|#38|#x26);/g, val : "&"};
|
||||
const htmlEntities = {
|
||||
"space": { regex: /&(nbsp|#160);/g, val: " " },
|
||||
// "lt" : { regex: /&(lt|#60);/g, val: "<" },
|
||||
// "gt" : { regex: /&(gt|#62);/g, val: ">" },
|
||||
// "amp" : { regex: /&(amp|#38);/g, val: "&" },
|
||||
// "quot" : { regex: /&(quot|#34);/g, val: "\"" },
|
||||
// "apos" : { regex: /&(apos|#39);/g, val: "'" },
|
||||
"cent" : { regex: /&(cent|#162);/g, val: "¢" },
|
||||
"pound" : { regex: /&(pound|#163);/g, val: "£" },
|
||||
"yen" : { regex: /&(yen|#165);/g, val: "¥" },
|
||||
"euro" : { regex: /&(euro|#8364);/g, val: "€" },
|
||||
"copyright" : { regex: /&(copy|#169);/g, val: "©" },
|
||||
"reg" : { regex: /&(reg|#174);/g, val: "®" },
|
||||
"inr" : { regex: /&(inr|#8377);/g, val: "₹" },
|
||||
"num_dec": { regex: /&#([0-9]{1,7});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 10)) },
|
||||
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 16)) },
|
||||
};
|
||||
|
||||
class EntitiesParser{
|
||||
constructor(replaceHtmlEntities) {
|
||||
this.replaceHtmlEntities = replaceHtmlEntities;
|
||||
this.docTypeEntities = {};
|
||||
this.lastEntities = {
|
||||
"apos" : { regex: /&(apos|#39|#x27);/g, val : "'"},
|
||||
"gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"},
|
||||
"lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"},
|
||||
"quot" : { regex: /&(quot|#34|#x22);/g, val : "\""},
|
||||
};
|
||||
}
|
||||
|
||||
addExternalEntities(externalEntities){
|
||||
const entKeys = Object.keys(externalEntities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.addExternalEntity(ent,externalEntities[ent])
|
||||
}
|
||||
}
|
||||
addExternalEntity(key,val){
|
||||
validateEntityName(key);
|
||||
if(val.indexOf("&") !== -1) {
|
||||
reportWarning(`Entity ${key} is not added as '&' is found in value;`)
|
||||
return;
|
||||
}else{
|
||||
this.lastEntities[ent] = {
|
||||
regex: new RegExp("&"+key+";","g"),
|
||||
val : val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDocTypeEntities(entities){
|
||||
const entKeys = Object.keys(entities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.docTypeEntities[ent] = {
|
||||
regex: new RegExp("&"+ent+";","g"),
|
||||
val : entities[ent]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parse(val){
|
||||
return this.replaceEntitiesValue(val)
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Replace DOCTYPE entities
|
||||
* 2. Replace external entities
|
||||
* 3. Replace HTML entities if asked
|
||||
* @param {string} val
|
||||
*/
|
||||
replaceEntitiesValue(val){
|
||||
if(typeof val === "string" && val.length > 0){
|
||||
for(let entityName in this.docTypeEntities){
|
||||
const entity = this.docTypeEntities[entityName];
|
||||
val = val.replace( entity.regx, entity.val);
|
||||
}
|
||||
for(let entityName in this.lastEntities){
|
||||
const entity = this.lastEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
if(this.replaceHtmlEntities){
|
||||
for(let entityName in htmlEntities){
|
||||
const entity = htmlEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
val = val.replace( ampEntity.regex, ampEntity.val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
//an entity name should not contains special characters that may be used in regex
|
||||
//Eg !?\\\/[]$%{}^&*()<>
|
||||
const specialChar = "!?\\\/[]$%{}^&*()<>|+";
|
||||
|
||||
function validateEntityName(name){
|
||||
for (let i = 0; i < specialChar.length; i++) {
|
||||
const ch = specialChar[i];
|
||||
if(name.indexOf(ch) !== -1) throw new Error(`Invalid character ${ch} in entity name`);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
module.exports = EntitiesParser;
|
23
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/booleanParser.js
generated
vendored
Normal file
23
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/booleanParser.js
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
class boolParser{
|
||||
constructor(trueList, falseList){
|
||||
if(trueList)
|
||||
this.trueList = trueList;
|
||||
else
|
||||
this.trueList = ["true"];
|
||||
|
||||
if(falseList)
|
||||
this.falseList = falseList;
|
||||
else
|
||||
this.falseList = ["false"];
|
||||
}
|
||||
parse(val){
|
||||
if (typeof val === 'string') {
|
||||
//TODO: performance: don't convert
|
||||
const temp = val.toLowerCase();
|
||||
if(this.trueList.indexOf(temp) !== -1) return true;
|
||||
else if(this.falseList.indexOf(temp) !== -1 ) return false;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
module.exports = boolParser;
|
20
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/booleanParserExt.js
generated
vendored
Normal file
20
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/booleanParserExt.js
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
function boolParserExt(val){
|
||||
if(isArray(val)){
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
val[i] = parse(val[i])
|
||||
}
|
||||
}else{
|
||||
val = parse(val)
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
function parse(val){
|
||||
if (typeof val === 'string') {
|
||||
const temp = val.toLowerCase();
|
||||
if(temp === 'true' || temp ==="yes" || temp==="1") return true;
|
||||
else if(temp === 'false' || temp ==="no" || temp==="0") return false;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
module.exports = boolParserExt;
|
40
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/currency.js
generated
vendored
Normal file
40
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/currency.js
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
const defaultOptions = {
|
||||
maxLength: 200,
|
||||
// locale: "en-IN"
|
||||
}
|
||||
const localeMap = {
|
||||
"$":"en-US",
|
||||
"€":"de-DE",
|
||||
"£":"en-GB",
|
||||
"¥":"ja-JP",
|
||||
"₹":"en-IN",
|
||||
}
|
||||
const sign = "(?:-|\+)?";
|
||||
const digitsAndSeparator = "(?:\d+|\d{1,3}(?:,\d{3})+)";
|
||||
const decimalPart = "(?:\.\d{1,2})?";
|
||||
const symbol = "(?:\$|€|¥|₹)?";
|
||||
|
||||
const currencyCheckRegex = /^\s*(?:-|\+)?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d{1,2})?\s*(?:\$|€|¥|₹)?\s*$/u;
|
||||
|
||||
class CurrencyParser{
|
||||
constructor(options){
|
||||
this.options = options || defaultOptions;
|
||||
}
|
||||
parse(val){
|
||||
if (typeof val === 'string' && val.length <= this.options.maxLength) {
|
||||
if(val.indexOf(",,") !== -1 && val.indexOf(".." !== -1)){
|
||||
const match = val.match(currencyCheckRegex);
|
||||
if(match){
|
||||
const locale = this.options.locale || localeMap[match[2]||match[5]||"₹"];
|
||||
const formatter = new Intl.NumberFormat(locale)
|
||||
val = val.replace(/[^0-9,.]/g, '').trim();
|
||||
val = Number(val.replace(formatter.format(1000)[1], ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
CurrencyParser.defaultOptions = defaultOptions;
|
||||
|
||||
module.exports = CurrencyParser;
|
14
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/join.js
generated
vendored
Normal file
14
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/join.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
*
|
||||
* @param {array} val
|
||||
* @param {string} by
|
||||
* @returns
|
||||
*/
|
||||
function join(val, by=" "){
|
||||
if(isArray(val)){
|
||||
val.join(by)
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
module.exports = join;
|
16
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/number.js
generated
vendored
Normal file
16
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/number.js
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
const toNumber = require("strnum");
|
||||
|
||||
|
||||
class numParser{
|
||||
constructor(options){
|
||||
this.options = options;
|
||||
}
|
||||
parse(val){
|
||||
if (typeof val === 'string') {
|
||||
val = toNumber(val,this.options);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = numParser;
|
8
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/trim.js
generated
vendored
Normal file
8
em2rp/node_modules/fast-xml-parser/src/v5/valueParsers/trim.js
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
class trimmer{
|
||||
parse(val){
|
||||
if(typeof val === "string") return val.trim();
|
||||
else return val;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = trimmer;
|
16
em2rp/node_modules/fast-xml-parser/src/v6/CharsSymbol.js
generated
vendored
Normal file
16
em2rp/node_modules/fast-xml-parser/src/v6/CharsSymbol.js
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
export default {
|
||||
"<" : "<", //tag start
|
||||
">" : ">", //tag end
|
||||
"/" : "/", //close tag
|
||||
"!" : "!", //comment or docttype
|
||||
"!--" : "!--", //comment
|
||||
"-->" : "-->", //comment end
|
||||
"?" : "?", //pi
|
||||
"?>" : "?>", //pi end
|
||||
"?xml" : "?xml", //pi end
|
||||
"![" : "![", //cdata
|
||||
"]]>" : "]]>", //cdata end
|
||||
"[" : "[",
|
||||
"-" : "-",
|
||||
"D" : "D",
|
||||
}
|
104
em2rp/node_modules/fast-xml-parser/src/v6/EntitiesParser.js
generated
vendored
Normal file
104
em2rp/node_modules/fast-xml-parser/src/v6/EntitiesParser.js
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
const ampEntity = { regex: /&(amp|#38|#x26);/g, val : "&"};
|
||||
const htmlEntities = {
|
||||
"space": { regex: /&(nbsp|#160);/g, val: " " },
|
||||
// "lt" : { regex: /&(lt|#60);/g, val: "<" },
|
||||
// "gt" : { regex: /&(gt|#62);/g, val: ">" },
|
||||
// "amp" : { regex: /&(amp|#38);/g, val: "&" },
|
||||
// "quot" : { regex: /&(quot|#34);/g, val: "\"" },
|
||||
// "apos" : { regex: /&(apos|#39);/g, val: "'" },
|
||||
"cent" : { regex: /&(cent|#162);/g, val: "¢" },
|
||||
"pound" : { regex: /&(pound|#163);/g, val: "£" },
|
||||
"yen" : { regex: /&(yen|#165);/g, val: "¥" },
|
||||
"euro" : { regex: /&(euro|#8364);/g, val: "€" },
|
||||
"copyright" : { regex: /&(copy|#169);/g, val: "©" },
|
||||
"reg" : { regex: /&(reg|#174);/g, val: "®" },
|
||||
"inr" : { regex: /&(inr|#8377);/g, val: "₹" },
|
||||
"num_dec": { regex: /&#([0-9]{1,7});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 10)) },
|
||||
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 16)) },
|
||||
};
|
||||
export default class EntitiesParser{
|
||||
constructor(replaceHtmlEntities) {
|
||||
this.replaceHtmlEntities = replaceHtmlEntities;
|
||||
this.docTypeEntities = {};
|
||||
this.lastEntities = {
|
||||
"apos" : { regex: /&(apos|#39|#x27);/g, val : "'"},
|
||||
"gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"},
|
||||
"lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"},
|
||||
"quot" : { regex: /&(quot|#34|#x22);/g, val : "\""},
|
||||
};
|
||||
}
|
||||
|
||||
addExternalEntities(externalEntities){
|
||||
const entKeys = Object.keys(externalEntities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.addExternalEntity(ent,externalEntities[ent])
|
||||
}
|
||||
}
|
||||
addExternalEntity(key,val){
|
||||
validateEntityName(key);
|
||||
if(val.indexOf("&") !== -1) {
|
||||
reportWarning(`Entity ${key} is not added as '&' is found in value;`)
|
||||
return;
|
||||
}else{
|
||||
this.lastEntities[ent] = {
|
||||
regex: new RegExp("&"+key+";","g"),
|
||||
val : val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDocTypeEntities(entities){
|
||||
const entKeys = Object.keys(entities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.docTypeEntities[ent] = {
|
||||
regex: new RegExp("&"+ent+";","g"),
|
||||
val : entities[ent]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parse(val){
|
||||
return this.replaceEntitiesValue(val)
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Replace DOCTYPE entities
|
||||
* 2. Replace external entities
|
||||
* 3. Replace HTML entities if asked
|
||||
* @param {string} val
|
||||
*/
|
||||
replaceEntitiesValue(val){
|
||||
if(typeof val === "string" && val.length > 0){
|
||||
for(let entityName in this.docTypeEntities){
|
||||
const entity = this.docTypeEntities[entityName];
|
||||
val = val.replace( entity.regx, entity.val);
|
||||
}
|
||||
for(let entityName in this.lastEntities){
|
||||
const entity = this.lastEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
if(this.replaceHtmlEntities){
|
||||
for(let entityName in htmlEntities){
|
||||
const entity = htmlEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
val = val.replace( ampEntity.regex, ampEntity.val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
//an entity name should not contains special characters that may be used in regex
|
||||
//Eg !?\\\/[]$%{}^&*()<>
|
||||
const specialChar = "!?\\\/[]$%{}^&*()<>|+";
|
||||
|
||||
function validateEntityName(name){
|
||||
for (let i = 0; i < specialChar.length; i++) {
|
||||
const ch = specialChar[i];
|
||||
if(name.indexOf(ch) !== -1) throw new Error(`Invalid character ${ch} in entity name`);
|
||||
}
|
||||
return name;
|
||||
}
|
61
em2rp/node_modules/fast-xml-parser/src/v6/OptionsBuilder.js
generated
vendored
Normal file
61
em2rp/node_modules/fast-xml-parser/src/v6/OptionsBuilder.js
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
import {JsObjOutputBuilder} from './OutputBuilders/JsObjBuilder.js';
|
||||
|
||||
export const defaultOptions = {
|
||||
preserveOrder: false,
|
||||
removeNSPrefix: false, // remove NS from tag name or attribute name if true
|
||||
//ignoreRootElement : false,
|
||||
stopNodes: [], //nested tags will not be parsed even for errors
|
||||
// isArray: () => false, //User will set it
|
||||
htmlEntities: false,
|
||||
// skipEmptyListItem: false
|
||||
tags:{
|
||||
unpaired: [],
|
||||
nameFor:{
|
||||
cdata: false,
|
||||
comment: false,
|
||||
text: '#text'
|
||||
},
|
||||
separateTextProperty: false,
|
||||
},
|
||||
attributes:{
|
||||
ignore: false,
|
||||
booleanType: true,
|
||||
entities: true,
|
||||
},
|
||||
|
||||
// select: ["img[src]"],
|
||||
// stop: ["anim", "[ads]"]
|
||||
only: [], // rest tags will be skipped. It will result in flat array
|
||||
hierarchy: false, //will be used when a particular tag is set to be parsed.
|
||||
skip: [], // will be skipped from parse result. on('skip') will be triggered
|
||||
|
||||
select: [], // on('select', tag => tag ) will be called if match
|
||||
stop: [], //given tagPath will not be parsed. innerXML will be set as string value
|
||||
OutputBuilder: new JsObjOutputBuilder(),
|
||||
};
|
||||
|
||||
export const buildOptions = function(options) {
|
||||
const finalOptions = { ... defaultOptions};
|
||||
copyProperties(finalOptions,options)
|
||||
return finalOptions;
|
||||
};
|
||||
|
||||
function copyProperties(target, source) {
|
||||
for (let key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
if (key === 'OutputBuilder') {
|
||||
target[key] = source[key];
|
||||
}else if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
||||
// Recursively copy nested properties
|
||||
if (typeof target[key] === 'undefined') {
|
||||
target[key] = {};
|
||||
}
|
||||
copyProperties(target[key], source[key]);
|
||||
} else {
|
||||
// Copy non-nested properties
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/BaseOutputBuilder.js
generated
vendored
Normal file
69
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/BaseOutputBuilder.js
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
export default class BaseOutputBuilder{
|
||||
constructor(){
|
||||
// this.attributes = {};
|
||||
}
|
||||
|
||||
addAttribute(name, value){
|
||||
if(this.options.onAttribute){
|
||||
//TODO: better to pass tag path
|
||||
const v = this.options.onAttribute(name, value, this.tagName);
|
||||
if(v) this.attributes[v.name] = v.value;
|
||||
}else{
|
||||
name = this.options.attributes.prefix + name + this.options.attributes.suffix;
|
||||
this.attributes[name] = this.parseValue(value, this.options.attributes.valueParsers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse value by chain of parsers
|
||||
* @param {string} val
|
||||
* @returns {any} parsed value if matching parser found
|
||||
*/
|
||||
parseValue = function(val, valParsers){
|
||||
for (let i = 0; i < valParsers.length; i++) {
|
||||
let valParser = valParsers[i];
|
||||
if(typeof valParser === "string"){
|
||||
valParser = this.registeredParsers[valParser];
|
||||
}
|
||||
if(valParser){
|
||||
val = valParser.parse(val);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* To add a nested empty tag.
|
||||
* @param {string} key
|
||||
* @param {any} val
|
||||
*/
|
||||
_addChild(key, val){}
|
||||
|
||||
/**
|
||||
* skip the comment if property is not set
|
||||
*/
|
||||
addComment(text){
|
||||
if(this.options.nameFor.comment)
|
||||
this._addChild(this.options.nameFor.comment, text);
|
||||
}
|
||||
|
||||
//store CDATA separately if property is set
|
||||
//otherwise add to tag's value
|
||||
addCdata(text){
|
||||
if (this.options.nameFor.cdata) {
|
||||
this._addChild(this.options.nameFor.cdata, text);
|
||||
} else {
|
||||
this.addRawValue(text || "");
|
||||
}
|
||||
}
|
||||
|
||||
addRawValue = text => this.addValue(text);
|
||||
|
||||
addDeclaration(){
|
||||
if(!this.options.declaration){
|
||||
}else{
|
||||
this.addPi("?xml");
|
||||
}
|
||||
this.attributes = {}
|
||||
}
|
||||
}
|
103
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsArrBuilder.js
generated
vendored
Normal file
103
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsArrBuilder.js
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
import {buildOptions,registerCommonValueParsers} from './ParserOptionsBuilder.js';
|
||||
|
||||
export default class OutputBuilder{
|
||||
constructor(options){
|
||||
this.options = buildOptions(options);
|
||||
this.registeredParsers = registerCommonValueParsers(this.options);
|
||||
}
|
||||
|
||||
registerValueParser(name,parserInstance){//existing name will override the parser without warning
|
||||
this.registeredParsers[name] = parserInstance;
|
||||
}
|
||||
|
||||
getInstance(parserOptions){
|
||||
return new JsArrBuilder(parserOptions, this.options, this.registeredParsers);
|
||||
}
|
||||
}
|
||||
|
||||
const rootName = '!js_arr';
|
||||
import BaseOutputBuilder from './BaseOutputBuilder.js';
|
||||
|
||||
class JsArrBuilder extends BaseOutputBuilder{
|
||||
|
||||
constructor(parserOptions, options,registeredParsers) {
|
||||
super();
|
||||
this.tagsStack = [];
|
||||
this.parserOptions = parserOptions;
|
||||
this.options = options;
|
||||
this.registeredParsers = registeredParsers;
|
||||
|
||||
this.root = new Node(rootName);
|
||||
this.currentNode = this.root;
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
addTag(tag){
|
||||
//when a new tag is added, it should be added as child of current node
|
||||
//TODO: shift this check to the parser
|
||||
if(tag.name === "__proto__") tag.name = "#__proto__";
|
||||
|
||||
this.tagsStack.push(this.currentNode);
|
||||
this.currentNode = new Node(tag.name, this.attributes);
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node should be added by checking user's preference
|
||||
* @param {Node} node
|
||||
* @returns boolean: true if the node should not be added
|
||||
*/
|
||||
closeTag(){
|
||||
const node = this.currentNode;
|
||||
this.currentNode = this.tagsStack.pop(); //set parent node in scope
|
||||
if(this.options.onClose !== undefined){
|
||||
//TODO TagPathMatcher
|
||||
const resultTag = this.options.onClose(node,
|
||||
new TagPathMatcher(this.tagsStack,node));
|
||||
|
||||
if(resultTag) return;
|
||||
}
|
||||
this.currentNode.child.push(node); //to parent node
|
||||
}
|
||||
|
||||
//Called by parent class methods
|
||||
_addChild(key, val){
|
||||
// if(key === "__proto__") tagName = "#__proto__";
|
||||
this.currentNode.child.push( {[key]: val });
|
||||
// this.currentNode.leafType = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text value child node
|
||||
* @param {string} text
|
||||
*/
|
||||
addValue(text){
|
||||
this.currentNode.child.push( {[this.options.nameFor.text]: this.parseValue(text, this.options.tags.valueParsers) });
|
||||
}
|
||||
|
||||
addPi(name){
|
||||
//TODO: set pi flag
|
||||
if(!this.options.ignorePiTags){
|
||||
const node = new Node(name, this.attributes);
|
||||
this.currentNode[":@"] = this.attributes;
|
||||
this.currentNode.child.push(node);
|
||||
}
|
||||
this.attributes = {};
|
||||
}
|
||||
getOutput(){
|
||||
return this.root.child[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Node{
|
||||
constructor(tagname, attributes){
|
||||
this.tagname = tagname;
|
||||
this.child = []; //nested tags, text, cdata, comments
|
||||
if(attributes && Object.keys(attributes).length > 0)
|
||||
this[":@"] = attributes;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OutputBuilder;
|
100
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsMinArrBuilder.js
generated
vendored
Normal file
100
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsMinArrBuilder.js
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
import {buildOptions,registerCommonValueParsers} from"./ParserOptionsBuilder";
|
||||
|
||||
export default class OutputBuilder{
|
||||
constructor(options){
|
||||
this.options = buildOptions(options);
|
||||
this.registeredParsers = registerCommonValueParsers(this.options);
|
||||
}
|
||||
|
||||
registerValueParser(name,parserInstance){//existing name will override the parser without warning
|
||||
this.registeredParsers[name] = parserInstance;
|
||||
}
|
||||
|
||||
getInstance(parserOptions){
|
||||
return new JsMinArrBuilder(parserOptions, this.options, this.registeredParsers);
|
||||
}
|
||||
}
|
||||
|
||||
import BaseOutputBuilder from "./BaseOutputBuilder.js";
|
||||
const rootName = '^';
|
||||
|
||||
class JsMinArrBuilder extends BaseOutputBuilder{
|
||||
|
||||
constructor(parserOptions, options,registeredParsers) {
|
||||
super();
|
||||
this.tagsStack = [];
|
||||
this.parserOptions = parserOptions;
|
||||
this.options = options;
|
||||
this.registeredParsers = registeredParsers;
|
||||
|
||||
this.root = {[rootName]: []};
|
||||
this.currentNode = this.root;
|
||||
this.currentNodeTagName = rootName;
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
addTag(tag){
|
||||
//when a new tag is added, it should be added as child of current node
|
||||
//TODO: shift this check to the parser
|
||||
if(tag.name === "__proto__") tag.name = "#__proto__";
|
||||
|
||||
this.tagsStack.push([this.currentNodeTagName,this.currentNode]); //this.currentNode is parent node here
|
||||
this.currentNodeTagName = tag.name;
|
||||
this.currentNode = { [tag.name]:[]}
|
||||
if(Object.keys(this.attributes).length > 0){
|
||||
this.currentNode[":@"] = this.attributes;
|
||||
this.attributes = {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node should be added by checking user's preference
|
||||
* @param {Node} node
|
||||
* @returns boolean: true if the node should not be added
|
||||
*/
|
||||
closeTag(){
|
||||
const node = this.currentNode;
|
||||
const nodeName = this.currentNodeTagName;
|
||||
const arr = this.tagsStack.pop(); //set parent node in scope
|
||||
this.currentNodeTagName = arr[0];
|
||||
this.currentNode = arr[1];
|
||||
|
||||
if(this.options.onClose !== undefined){
|
||||
//TODO TagPathMatcher
|
||||
const resultTag = this.options.onClose(node,
|
||||
new TagPathMatcher(this.tagsStack,node));
|
||||
|
||||
if(resultTag) return;
|
||||
}
|
||||
this.currentNode[this.currentNodeTagName].push(node); //to parent node
|
||||
}
|
||||
|
||||
//Called by parent class methods
|
||||
_addChild(key, val){
|
||||
// if(key === "__proto__") tagName = "#__proto__";
|
||||
this.currentNode.push( {[key]: val });
|
||||
// this.currentNode.leafType = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text value child node
|
||||
* @param {string} text
|
||||
*/
|
||||
addValue(text){
|
||||
this.currentNode[this.currentNodeTagName].push( {[this.options.nameFor.text]: this.parseValue(text, this.options.tags.valueParsers) });
|
||||
}
|
||||
|
||||
addPi(name){
|
||||
if(!this.options.ignorePiTags){
|
||||
const node = { [name]:[]}
|
||||
if(this.attributes){
|
||||
node[":@"] = this.attributes;
|
||||
}
|
||||
this.currentNode.push(node);
|
||||
}
|
||||
this.attributes = {};
|
||||
}
|
||||
getOutput(){
|
||||
return this.root[rootName];
|
||||
}
|
||||
}
|
154
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsObjBuilder.js
generated
vendored
Normal file
154
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/JsObjBuilder.js
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
|
||||
|
||||
import {buildOptions,registerCommonValueParsers} from './ParserOptionsBuilder.js';
|
||||
|
||||
export default class OutputBuilder{
|
||||
constructor(builderOptions){
|
||||
this.options = buildOptions(builderOptions);
|
||||
this.registeredParsers = registerCommonValueParsers(this.options);
|
||||
}
|
||||
|
||||
registerValueParser(name,parserInstance){//existing name will override the parser without warning
|
||||
this.registeredParsers[name] = parserInstance;
|
||||
}
|
||||
|
||||
getInstance(parserOptions){
|
||||
return new JsObjBuilder(parserOptions, this.options, this.registeredParsers);
|
||||
}
|
||||
}
|
||||
|
||||
import BaseOutputBuilder from './BaseOutputBuilder.js';
|
||||
const rootName = '^';
|
||||
|
||||
class JsObjBuilder extends BaseOutputBuilder{
|
||||
|
||||
constructor(parserOptions, builderOptions,registeredParsers) {
|
||||
super();
|
||||
//hold the raw detail of a tag and sequence with reference to the output
|
||||
this.tagsStack = [];
|
||||
this.parserOptions = parserOptions;
|
||||
this.options = builderOptions;
|
||||
this.registeredParsers = registeredParsers;
|
||||
|
||||
this.root = {};
|
||||
this.parent = this.root;
|
||||
this.tagName = rootName;
|
||||
this.value = {};
|
||||
this.textValue = "";
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
addTag(tag){
|
||||
|
||||
let value = "";
|
||||
if( !isEmpty(this.attributes)){
|
||||
value = {};
|
||||
if(this.options.attributes.groupBy){
|
||||
value[this.options.attributes.groupBy] = this.attributes;
|
||||
}else{
|
||||
value = this.attributes;
|
||||
}
|
||||
}
|
||||
|
||||
this.tagsStack.push([this.tagName, this.textValue, this.value]); //parent tag, parent text value, parent tag value (jsobj)
|
||||
this.tagName = tag.name;
|
||||
this.value = value;
|
||||
this.textValue = "";
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node should be added by checking user's preference
|
||||
* @param {Node} node
|
||||
* @returns boolean: true if the node should not be added
|
||||
*/
|
||||
closeTag(){
|
||||
const tagName = this.tagName;
|
||||
let value = this.value;
|
||||
let textValue = this.textValue;
|
||||
|
||||
//update tag text value
|
||||
if(typeof value !== "object" && !Array.isArray(value)){
|
||||
value = this.parseValue(textValue.trim(), this.options.tags.valueParsers);
|
||||
}else if(textValue.length > 0){
|
||||
value[this.options.nameFor.text] = this.parseValue(textValue.trim(), this.options.tags.valueParsers);
|
||||
}
|
||||
|
||||
|
||||
let resultTag= {
|
||||
tagName: tagName,
|
||||
value: value
|
||||
};
|
||||
|
||||
if(this.options.onTagClose !== undefined){
|
||||
//TODO TagPathMatcher
|
||||
resultTag = this.options.onClose(tagName, value, this.textValue, new TagPathMatcher(this.tagsStack,node));
|
||||
|
||||
if(!resultTag) return;
|
||||
}
|
||||
|
||||
//set parent node in scope
|
||||
let arr = this.tagsStack.pop();
|
||||
let parentTag = arr[2];
|
||||
parentTag=this._addChildTo(resultTag.tagName, resultTag.value, parentTag);
|
||||
|
||||
this.tagName = arr[0];
|
||||
this.textValue = arr[1];
|
||||
this.value = parentTag;
|
||||
}
|
||||
|
||||
_addChild(key, val){
|
||||
if(typeof this.value === "string"){
|
||||
this.value = { [this.options.nameFor.text] : this.value };
|
||||
}
|
||||
|
||||
this._addChildTo(key, val, this.value);
|
||||
// this.currentNode.leafType = false;
|
||||
this.attributes = {};
|
||||
}
|
||||
|
||||
_addChildTo(key, val, node){
|
||||
if(typeof node === 'string') node = {};
|
||||
if(!node[key]){
|
||||
node[key] = val;
|
||||
}else{ //Repeated
|
||||
if(!Array.isArray(node[key])){ //but not stored as array
|
||||
node[key] = [node[key]];
|
||||
}
|
||||
node[key].push(val);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add text value child node
|
||||
* @param {string} text
|
||||
*/
|
||||
addValue(text){
|
||||
//TODO: use bytes join
|
||||
if(this.textValue.length > 0) this.textValue += " " + text;
|
||||
else this.textValue = text;
|
||||
}
|
||||
|
||||
addPi(name){
|
||||
let value = "";
|
||||
if( !isEmpty(this.attributes)){
|
||||
value = {};
|
||||
if(this.options.attributes.groupBy){
|
||||
value[this.options.attributes.groupBy] = this.attributes;
|
||||
}else{
|
||||
value = this.attributes;
|
||||
}
|
||||
}
|
||||
this._addChild(name, value);
|
||||
|
||||
}
|
||||
getOutput(){
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
function isEmpty(obj) {
|
||||
return Object.keys(obj).length === 0;
|
||||
}
|
94
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/ParserOptionsBuilder.js
generated
vendored
Normal file
94
em2rp/node_modules/fast-xml-parser/src/v6/OutputBuilders/ParserOptionsBuilder.js
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
import trimParser from "../valueParsers/trim";
|
||||
import booleanParser from "../valueParsers/booleanParser";
|
||||
import currencyParser from "../valueParsers/currency";
|
||||
import numberParser from "../valueParsers/number";
|
||||
|
||||
const defaultOptions={
|
||||
nameFor:{
|
||||
text: "#text",
|
||||
comment: "",
|
||||
cdata: "",
|
||||
},
|
||||
// onTagClose: () => {},
|
||||
// onAttribute: () => {},
|
||||
piTag: false,
|
||||
declaration: false, //"?xml"
|
||||
tags: {
|
||||
valueParsers: [
|
||||
// "trim",
|
||||
// "boolean",
|
||||
// "number",
|
||||
// "currency",
|
||||
// "date",
|
||||
]
|
||||
},
|
||||
attributes:{
|
||||
prefix: "@_",
|
||||
suffix: "",
|
||||
groupBy: "",
|
||||
|
||||
valueParsers: [
|
||||
// "trim",
|
||||
// "boolean",
|
||||
// "number",
|
||||
// "currency",
|
||||
// "date",
|
||||
]
|
||||
},
|
||||
dataType:{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
const withJoin = ["trim","join", /*"entities",*/"number","boolean","currency"/*, "date"*/]
|
||||
const withoutJoin = ["trim", /*"entities",*/"number","boolean","currency"/*, "date"*/]
|
||||
|
||||
export function buildOptions(options){
|
||||
//clone
|
||||
const finalOptions = { ... defaultOptions};
|
||||
|
||||
//add config missed in cloning
|
||||
finalOptions.tags.valueParsers.push(...withJoin)
|
||||
if(!this.preserveOrder)
|
||||
finalOptions.tags.valueParsers.push(...withoutJoin);
|
||||
|
||||
//add config missed in cloning
|
||||
finalOptions.attributes.valueParsers.push(...withJoin)
|
||||
|
||||
//override configuration
|
||||
copyProperties(finalOptions,options);
|
||||
return finalOptions;
|
||||
}
|
||||
|
||||
function copyProperties(target, source) {
|
||||
for (let key in source) {
|
||||
if (source.hasOwnProperty(key)) {
|
||||
if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
||||
// Recursively copy nested properties
|
||||
if (typeof target[key] === 'undefined') {
|
||||
target[key] = {};
|
||||
}
|
||||
copyProperties(target[key], source[key]);
|
||||
} else {
|
||||
// Copy non-nested properties
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function registerCommonValueParsers(options){
|
||||
return {
|
||||
"trim": new trimParser(),
|
||||
// "join": this.entityParser.parse,
|
||||
"boolean": new booleanParser(),
|
||||
"number": new numberParser({
|
||||
hex: true,
|
||||
leadingZeros: true,
|
||||
eNotation: true
|
||||
}),
|
||||
"currency": new currencyParser(),
|
||||
// "date": this.entityParser.parse,
|
||||
}
|
||||
}
|
0
em2rp/node_modules/fast-xml-parser/src/v6/Report.js
generated
vendored
Normal file
0
em2rp/node_modules/fast-xml-parser/src/v6/Report.js
generated
vendored
Normal file
81
em2rp/node_modules/fast-xml-parser/src/v6/TagPath.js
generated
vendored
Normal file
81
em2rp/node_modules/fast-xml-parser/src/v6/TagPath.js
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
export default class TagPath{
|
||||
constructor(pathStr){
|
||||
let text = "";
|
||||
let tName = "";
|
||||
let pos;
|
||||
let aName = "";
|
||||
let aVal = "";
|
||||
this.stack = []
|
||||
|
||||
for (let i = 0; i < pathStr.length; i++) {
|
||||
let ch = pathStr[i];
|
||||
if(ch === " ") {
|
||||
if(text.length === 0) continue;
|
||||
tName = text; text = "";
|
||||
}else if(ch === "["){
|
||||
if(tName.length === 0){
|
||||
tName = text; text = "";
|
||||
}
|
||||
i++;
|
||||
for (; i < pathStr.length; i++) {
|
||||
ch = pathStr[i];
|
||||
if(ch=== "=") continue;
|
||||
else if(ch=== "]") {aName = text.trim(); text=""; break; i--;}
|
||||
else if(ch === "'" || ch === '"'){
|
||||
let attrEnd = pathStr.indexOf(ch,i+1);
|
||||
aVal = pathStr.substring(i+1, attrEnd);
|
||||
i = attrEnd;
|
||||
}else{
|
||||
text +=ch;
|
||||
}
|
||||
}
|
||||
}else if(ch !== " " && text.length === 0 && tName.length > 0){//reading tagName
|
||||
//save previous tag
|
||||
this.stack.push(new TagPathNode(tName,pos,aName,aVal));
|
||||
text = ch; tName = ""; aName = ""; aVal = "";
|
||||
}else{
|
||||
text+=ch;
|
||||
}
|
||||
}
|
||||
|
||||
//last tag in the path
|
||||
if(tName.length >0 || text.length>0){
|
||||
this.stack.push(new TagPathNode(text||tName,pos,aName,aVal));
|
||||
}
|
||||
}
|
||||
|
||||
match(tagStack,node){
|
||||
if(this.stack[0].name !== "*"){
|
||||
if(this.stack.length !== tagStack.length +1) return false;
|
||||
|
||||
//loop through tagPath and tagStack and match
|
||||
for (let i = 0; i < this.tagStack.length; i++) {
|
||||
if(!this.stack[i].match(tagStack[i])) return false;
|
||||
}
|
||||
}
|
||||
if(!this.stack[this.stack.length - 1].match(node)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class TagPathNode{
|
||||
constructor(name,position,attrName,attrVal){
|
||||
this.name = name;
|
||||
this.position = position;
|
||||
this.attrName = attrName,
|
||||
this.attrVal = attrVal;
|
||||
}
|
||||
|
||||
match(node){
|
||||
let matching = true;
|
||||
matching = node.name === this.name;
|
||||
if(this.position) matching = node.position === this.position;
|
||||
if(this.attrName) matching = node.attrs[this.attrName !== undefined];
|
||||
if(this.attrVal) matching = node.attrs[this.attrName !== this.attrVal];
|
||||
return matching;
|
||||
}
|
||||
}
|
||||
|
||||
// console.log((new TagPath("* b[b]")).stack);
|
||||
// console.log((new TagPath("a[a] b[b] c")).stack);
|
||||
// console.log((new TagPath(" b [ b= 'cf sdadwa' ] a ")).stack);
|
13
em2rp/node_modules/fast-xml-parser/src/v6/TagPathMatcher.js
generated
vendored
Normal file
13
em2rp/node_modules/fast-xml-parser/src/v6/TagPathMatcher.js
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import {TagPath} from './TagPath.js';
|
||||
|
||||
export default class TagPathMatcher{
|
||||
constructor(stack,node){
|
||||
this.stack = stack;
|
||||
this.node= node;
|
||||
}
|
||||
|
||||
match(path){
|
||||
const tagPath = new TagPath(path);
|
||||
return tagPath.match(this.stack, this.node);
|
||||
}
|
||||
}
|
83
em2rp/node_modules/fast-xml-parser/src/v6/XMLParser.js
generated
vendored
Normal file
83
em2rp/node_modules/fast-xml-parser/src/v6/XMLParser.js
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
import { buildOptions} from './OptionsBuilder.js';
|
||||
import Xml2JsParser from './Xml2JsParser.js';
|
||||
|
||||
export default class XMLParser{
|
||||
|
||||
constructor(options){
|
||||
this.externalEntities = {};
|
||||
this.options = buildOptions(options);
|
||||
// console.log(this.options)
|
||||
}
|
||||
/**
|
||||
* Parse XML data string to JS object
|
||||
* @param {string|Buffer} xmlData
|
||||
* @param {boolean|Object} validationOption
|
||||
*/
|
||||
parse(xmlData){
|
||||
if(Array.isArray(xmlData) && xmlData.byteLength !== undefined){
|
||||
return this.parse(xmlData);
|
||||
}else if( xmlData.toString){
|
||||
xmlData = xmlData.toString();
|
||||
}else{
|
||||
throw new Error("XML data is accepted in String or Bytes[] form.")
|
||||
}
|
||||
// if( validationOption){
|
||||
// if(validationOption === true) validationOption = {}; //validate with default options
|
||||
|
||||
// const result = validator.validate(xmlData, validationOption);
|
||||
// if (result !== true) {
|
||||
// throw Error( `${result.err.msg}:${result.err.line}:${result.err.col}` )
|
||||
// }
|
||||
// }
|
||||
const parser = new Xml2JsParser(this.options);
|
||||
parser.entityParser.addExternalEntities(this.externalEntities);
|
||||
return parser.parse(xmlData);
|
||||
}
|
||||
/**
|
||||
* Parse XML data buffer to JS object
|
||||
* @param {string|Buffer} xmlData
|
||||
* @param {boolean|Object} validationOption
|
||||
*/
|
||||
parseBytesArr(xmlData){
|
||||
if(Array.isArray(xmlData) && xmlData.byteLength !== undefined){
|
||||
}else{
|
||||
throw new Error("XML data is accepted in Bytes[] form.")
|
||||
}
|
||||
const parser = new Xml2JsParser(this.options);
|
||||
parser.entityParser.addExternalEntities(this.externalEntities);
|
||||
return parser.parseBytesArr(xmlData);
|
||||
}
|
||||
/**
|
||||
* Parse XML data stream to JS object
|
||||
* @param {fs.ReadableStream} xmlDataStream
|
||||
*/
|
||||
parseStream(xmlDataStream){
|
||||
if(!isStream(xmlDataStream)) throw new Error("FXP: Invalid stream input");
|
||||
|
||||
const orderedObjParser = new Xml2JsParser(this.options);
|
||||
orderedObjParser.entityParser.addExternalEntities(this.externalEntities);
|
||||
return orderedObjParser.parseStream(xmlDataStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Entity which is not by default supported by this library
|
||||
* @param {string} key
|
||||
* @param {string} value
|
||||
*/
|
||||
addEntity(key, value){
|
||||
if(value.indexOf("&") !== -1){
|
||||
throw new Error("Entity value can't have '&'")
|
||||
}else if(key.indexOf("&") !== -1 || key.indexOf(";") !== -1){
|
||||
throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '
'")
|
||||
}else if(value === "&"){
|
||||
throw new Error("An entity with value '&' is not permitted");
|
||||
}else{
|
||||
this.externalEntities[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isStream(stream){
|
||||
if(stream && typeof stream.read === "function" && typeof stream.on === "function" && typeof stream.readableEnded === "boolean") return true;
|
||||
return false;
|
||||
}
|
235
em2rp/node_modules/fast-xml-parser/src/v6/Xml2JsParser.js
generated
vendored
Normal file
235
em2rp/node_modules/fast-xml-parser/src/v6/Xml2JsParser.js
generated
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
import StringSource from './inputSource/StringSource.js';
|
||||
import BufferSource from './inputSource/BufferSource.js';
|
||||
import {readTagExp,readClosingTagName} from './XmlPartReader.js';
|
||||
import {readComment, readCdata,readDocType,readPiTag} from './XmlSpecialTagsReader.js';
|
||||
import TagPath from './TagPath.js';
|
||||
import TagPathMatcher from './TagPathMatcher.js';
|
||||
import EntitiesParser from './EntitiesParser.js';
|
||||
|
||||
//To hold the data of current tag
|
||||
//This is usually used to compare jpath expression against current tag
|
||||
class TagDetail{
|
||||
constructor(name){
|
||||
this.name = name;
|
||||
this.position = 0;
|
||||
// this.attributes = {};
|
||||
}
|
||||
}
|
||||
|
||||
export default class Xml2JsParser {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
|
||||
this.currentTagDetail = null;
|
||||
this.tagTextData = "";
|
||||
this.tagsStack = [];
|
||||
this.entityParser = new EntitiesParser(options.htmlEntities);
|
||||
this.stopNodes = [];
|
||||
for (let i = 0; i < this.options.stopNodes.length; i++) {
|
||||
this.stopNodes.push(new TagPath(this.options.stopNodes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
parse(strData) {
|
||||
this.source = new StringSource(strData);
|
||||
this.parseXml();
|
||||
return this.outputBuilder.getOutput();
|
||||
}
|
||||
parseBytesArr(data) {
|
||||
this.source = new BufferSource(data );
|
||||
this.parseXml();
|
||||
return this.outputBuilder.getOutput();
|
||||
}
|
||||
|
||||
parseXml() {
|
||||
//TODO: Separate TagValueParser as separate class. So no scope issue in node builder class
|
||||
|
||||
//OutputBuilder should be set in XML Parser
|
||||
this.outputBuilder = this.options.OutputBuilder.getInstance(this.options);
|
||||
this.root = { root: true};
|
||||
this.currentTagDetail = this.root;
|
||||
|
||||
while(this.source.canRead()){
|
||||
let ch = this.source.readCh();
|
||||
if (ch === "") break;
|
||||
|
||||
if(ch === "<"){//tagStart
|
||||
let nextChar = this.source.readChAt(0);
|
||||
if (nextChar === "" ) throw new Error("Unexpected end of source");
|
||||
|
||||
|
||||
if(nextChar === "!" || nextChar === "?"){
|
||||
this.source.updateBufferBoundary();
|
||||
//previously collected text should be added to current node
|
||||
this.addTextNode();
|
||||
|
||||
this.readSpecialTag(nextChar);// Read DOCTYPE, comment, CDATA, PI tag
|
||||
}else if(nextChar === "/"){
|
||||
this.source.updateBufferBoundary();
|
||||
this.readClosingTag();
|
||||
// console.log(this.source.buffer.length, this.source.readable);
|
||||
// console.log(this.tagsStack.length);
|
||||
}else{//opening tag
|
||||
this.readOpeningTag();
|
||||
}
|
||||
}else{
|
||||
this.tagTextData += ch;
|
||||
}
|
||||
}//End While loop
|
||||
if(this.tagsStack.length > 0 || ( this.tagTextData !== "undefined" && this.tagTextData.trimEnd().length > 0) ) throw new Error("Unexpected data in the end of document");
|
||||
}
|
||||
|
||||
/**
|
||||
* read closing paired tag. Set parent tag in scope.
|
||||
* skip a node on user's choice
|
||||
*/
|
||||
readClosingTag(){
|
||||
const tagName = this.processTagName(readClosingTagName(this.source));
|
||||
// console.log(tagName, this.tagsStack.length);
|
||||
this.validateClosingTag(tagName);
|
||||
// All the text data collected, belongs to current tag.
|
||||
if(!this.currentTagDetail.root) this.addTextNode();
|
||||
this.outputBuilder.closeTag();
|
||||
// Since the tag is closed now, parent tag comes in scope
|
||||
this.currentTagDetail = this.tagsStack.pop();
|
||||
}
|
||||
|
||||
validateClosingTag(tagName){
|
||||
// This can't be unpaired tag, or a stop tag.
|
||||
if(this.isUnpaired(tagName) || this.isStopNode(tagName)) throw new Error(`Unexpected closing tag '${tagName}'`);
|
||||
// This must match with last opening tag
|
||||
else if(tagName !== this.currentTagDetail.name)
|
||||
throw new Error(`Unexpected closing tag '${tagName}' expecting '${this.currentTagDetail.name}'`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Read paired, unpaired, self-closing, stop and special tags.
|
||||
* Create a new node
|
||||
* Push paired tag in stack.
|
||||
*/
|
||||
readOpeningTag(){
|
||||
//save previously collected text data to current node
|
||||
this.addTextNode();
|
||||
|
||||
//create new tag
|
||||
let tagExp = readTagExp(this, ">" );
|
||||
|
||||
// process and skip from tagsStack For unpaired tag, self closing tag, and stop node
|
||||
const tagDetail = new TagDetail(tagExp.tagName);
|
||||
if(this.isUnpaired(tagExp.tagName)) {
|
||||
//TODO: this will lead 2 extra stack operation
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.outputBuilder.closeTag();
|
||||
} else if(tagExp.selfClosing){
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.outputBuilder.closeTag();
|
||||
} else if(this.isStopNode(this.currentTagDetail)){
|
||||
// TODO: let's user set a stop node boundary detector for complex contents like script tag
|
||||
//TODO: pass tag name only to avoid string operations
|
||||
const content = source.readUptoCloseTag(`</${tagExp.tagName}`);
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.outputBuilder.addValue(content);
|
||||
this.outputBuilder.closeTag();
|
||||
}else{//paired tag
|
||||
//set new nested tag in scope.
|
||||
this.tagsStack.push(this.currentTagDetail);
|
||||
this.outputBuilder.addTag(tagDetail);
|
||||
this.currentTagDetail = tagDetail;
|
||||
}
|
||||
// console.log(tagExp.tagName,this.tagsStack.length);
|
||||
// this.options.onClose()
|
||||
|
||||
}
|
||||
|
||||
readSpecialTag(startCh){
|
||||
if(startCh == "!"){
|
||||
let nextChar = this.source.readCh();
|
||||
if (nextChar === null || nextChar === undefined) throw new Error("Unexpected ending of the source");
|
||||
|
||||
if(nextChar === "-"){//comment
|
||||
readComment(this);
|
||||
}else if(nextChar === "["){//CDATA
|
||||
readCdata(this);
|
||||
}else if(nextChar === "D"){//DOCTYPE
|
||||
readDocType(this);
|
||||
}
|
||||
}else if(startCh === "?"){
|
||||
readPiTag(this);
|
||||
}else{
|
||||
throw new Error(`Invalid tag '<${startCh}' at ${this.source.line}:${this.source.col}`)
|
||||
}
|
||||
}
|
||||
addTextNode = function() {
|
||||
// if(this.currentTagDetail){
|
||||
//save text as child node
|
||||
// if(this.currentTagDetail.tagname !== '!xml')
|
||||
if (this.tagTextData !== undefined && this.tagTextData !== "") { //store previously collected data as textNode
|
||||
if(this.tagTextData.trim().length > 0){
|
||||
//TODO: shift parsing to output builder
|
||||
|
||||
this.outputBuilder.addValue(this.replaceEntities(this.tagTextData));
|
||||
}
|
||||
this.tagTextData = "";
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
processAttrName(name){
|
||||
if(name === "__proto__") name = "#__proto__";
|
||||
name = resolveNameSpace(name, this.removeNSPrefix);
|
||||
return name;
|
||||
}
|
||||
|
||||
processTagName(name){
|
||||
if(name === "__proto__") name = "#__proto__";
|
||||
name = resolveNameSpace(name, this.removeNSPrefix);
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate tags path from tagsStack
|
||||
*/
|
||||
tagsPath(tagName){
|
||||
//TODO: return TagPath Object. User can call match method with path
|
||||
return "";
|
||||
}
|
||||
|
||||
isUnpaired(tagName){
|
||||
return this.options.tags.unpaired.indexOf(tagName) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* valid expressions are
|
||||
* tag nested
|
||||
* * nested
|
||||
* tag nested[attribute]
|
||||
* tag nested[attribute=""]
|
||||
* tag nested[attribute!=""]
|
||||
* tag nested:0 //for future
|
||||
* @param {string} tagName
|
||||
* @returns
|
||||
*/
|
||||
isStopNode(node){
|
||||
for (let i = 0; i < this.stopNodes.length; i++) {
|
||||
const givenPath = this.stopNodes[i];
|
||||
if(givenPath.match(this.tagsStack, node)) return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
replaceEntities(text){
|
||||
//TODO: if option is set then replace entities
|
||||
return this.entityParser.parse(text)
|
||||
}
|
||||
}
|
||||
|
||||
function resolveNameSpace(name, removeNSPrefix) {
|
||||
if (removeNSPrefix) {
|
||||
const parts = name.split(':');
|
||||
if(parts.length === 2){
|
||||
if (parts[0] === 'xmlns') return '';
|
||||
else return parts[1];
|
||||
}else reportError(`Multiple namespaces ${name}`)
|
||||
}
|
||||
return name;
|
||||
}
|
210
em2rp/node_modules/fast-xml-parser/src/v6/XmlPartReader.js
generated
vendored
Normal file
210
em2rp/node_modules/fast-xml-parser/src/v6/XmlPartReader.js
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* find paired tag for a stop node
|
||||
* @param {string} xmlDoc
|
||||
* @param {string} tagName
|
||||
* @param {number} i : start index
|
||||
*/
|
||||
export function readStopNode(xmlDoc, tagName, i){
|
||||
const startIndex = i;
|
||||
// Starting at 1 since we already have an open tag
|
||||
let openTagCount = 1;
|
||||
|
||||
for (; i < xmlDoc.length; i++) {
|
||||
if( xmlDoc[i] === "<"){
|
||||
if (xmlDoc[i+1] === "/") {//close tag
|
||||
const closeIndex = findSubStrIndex(xmlDoc, ">", i, `${tagName} is not closed`);
|
||||
let closeTagName = xmlDoc.substring(i+2,closeIndex).trim();
|
||||
if(closeTagName === tagName){
|
||||
openTagCount--;
|
||||
if (openTagCount === 0) {
|
||||
return {
|
||||
tagContent: xmlDoc.substring(startIndex, i),
|
||||
i : closeIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
i=closeIndex;
|
||||
} else if(xmlDoc[i+1] === '?') {
|
||||
const closeIndex = findSubStrIndex(xmlDoc, "?>", i+1, "StopNode is not closed.")
|
||||
i=closeIndex;
|
||||
} else if(xmlDoc.substr(i + 1, 3) === '!--') {
|
||||
const closeIndex = findSubStrIndex(xmlDoc, "-->", i+3, "StopNode is not closed.")
|
||||
i=closeIndex;
|
||||
} else if(xmlDoc.substr(i + 1, 2) === '![') {
|
||||
const closeIndex = findSubStrIndex(xmlDoc, "]]>", i, "StopNode is not closed.") - 2;
|
||||
i=closeIndex;
|
||||
} else {
|
||||
const tagData = readTagExp(xmlDoc, i, '>')
|
||||
|
||||
if (tagData) {
|
||||
const openTagName = tagData && tagData.tagName;
|
||||
if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length-1] !== "/") {
|
||||
openTagCount++;
|
||||
}
|
||||
i=tagData.closeIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}//end for loop
|
||||
}
|
||||
|
||||
/**
|
||||
* Read closing tag name
|
||||
* @param {Source} source
|
||||
* @returns tag name
|
||||
*/
|
||||
export function readClosingTagName(source){
|
||||
let text = ""; //temporary data
|
||||
while(source.canRead()){
|
||||
let ch = source.readCh();
|
||||
// if (ch === null || ch === undefined) break;
|
||||
// source.updateBuffer();
|
||||
|
||||
if (ch === ">") return text.trimEnd();
|
||||
else text += ch;
|
||||
}
|
||||
throw new Error(`Unexpected end of source. Reading '${substr}'`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read XML tag and build attributes map
|
||||
* This function can be used to read normal tag, pi tag.
|
||||
* This function can't be used to read comment, CDATA, DOCTYPE.
|
||||
* Eg <tag attr = ' some"' attr= ">" bool>
|
||||
* @param {string} xmlDoc
|
||||
* @param {number} startIndex starting index
|
||||
* @returns tag expression includes tag name & attribute string
|
||||
*/
|
||||
export function readTagExp(parser) {
|
||||
let inSingleQuotes = false;
|
||||
let inDoubleQuotes = false;
|
||||
let i;
|
||||
let EOE = false;
|
||||
|
||||
for (i = 0; parser.source.canRead(i); i++) {
|
||||
const char = parser.source.readChAt(i);
|
||||
|
||||
if (char === "'" && !inDoubleQuotes) {
|
||||
inSingleQuotes = !inSingleQuotes;
|
||||
} else if (char === '"' && !inSingleQuotes) {
|
||||
inDoubleQuotes = !inDoubleQuotes;
|
||||
} else if (char === '>' && !inSingleQuotes && !inDoubleQuotes) {
|
||||
// If not inside quotes, stop reading at '>'
|
||||
EOE = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if(inSingleQuotes || inDoubleQuotes){
|
||||
throw new Error("Invalid attribute expression. Quote is not properly closed");
|
||||
}else if(!EOE) throw new Error("Unexpected closing of source. Waiting for '>'");
|
||||
|
||||
|
||||
const exp = parser.source.readStr(i);
|
||||
parser.source.updateBufferBoundary(i + 1);
|
||||
return buildTagExpObj(exp, parser)
|
||||
}
|
||||
|
||||
export function readPiExp(parser) {
|
||||
let inSingleQuotes = false;
|
||||
let inDoubleQuotes = false;
|
||||
let i;
|
||||
let EOE = false;
|
||||
|
||||
for (i = 0; parser.source.canRead(i) ; i++) {
|
||||
const currentChar = parser.source.readChAt(i);
|
||||
const nextChar = parser.source.readChAt(i+1);
|
||||
|
||||
if (currentChar === "'" && !inDoubleQuotes) {
|
||||
inSingleQuotes = !inSingleQuotes;
|
||||
} else if (currentChar === '"' && !inSingleQuotes) {
|
||||
inDoubleQuotes = !inDoubleQuotes;
|
||||
}
|
||||
|
||||
if (!inSingleQuotes && !inDoubleQuotes) {
|
||||
if (currentChar === '?' && nextChar === '>') {
|
||||
EOE = true;
|
||||
break; // Exit the loop when '?>' is found
|
||||
}
|
||||
}
|
||||
}
|
||||
if(inSingleQuotes || inDoubleQuotes){
|
||||
throw new Error("Invalid attribute expression. Quote is not properly closed in PI tag expression");
|
||||
}else if(!EOE) throw new Error("Unexpected closing of source. Waiting for '?>'");
|
||||
|
||||
if(!parser.options.attributes.ignore){
|
||||
//TODO: use regex to verify attributes if not set to ignore
|
||||
}
|
||||
|
||||
const exp = parser.source.readStr(i);
|
||||
parser.source.updateBufferBoundary(i + 1);
|
||||
return buildTagExpObj(exp, parser)
|
||||
}
|
||||
|
||||
function buildTagExpObj(exp, parser){
|
||||
const tagExp = {
|
||||
tagName: "",
|
||||
selfClosing: false
|
||||
};
|
||||
let attrsExp = "";
|
||||
|
||||
// Check for self-closing tag before setting the name
|
||||
if(exp[exp.length -1] === "/") {
|
||||
tagExp.selfClosing = true;
|
||||
exp = exp.slice(0, -1); // Remove the trailing slash
|
||||
}
|
||||
|
||||
//separate tag name
|
||||
let i = 0;
|
||||
for (; i < exp.length; i++) {
|
||||
const char = exp[i];
|
||||
if(char === " "){
|
||||
tagExp.tagName = exp.substring(0, i);
|
||||
attrsExp = exp.substring(i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//only tag
|
||||
if(tagExp.tagName.length === 0 && i === exp.length)tagExp.tagName = exp;
|
||||
|
||||
tagExp.tagName = tagExp.tagName.trimEnd();
|
||||
|
||||
if(!parser.options.attributes.ignore && attrsExp.length > 0){
|
||||
parseAttributesExp(attrsExp,parser)
|
||||
}
|
||||
|
||||
return tagExp;
|
||||
}
|
||||
|
||||
const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm');
|
||||
|
||||
function parseAttributesExp(attrStr, parser) {
|
||||
const matches = getAllMatches(attrStr, attrsRegx);
|
||||
const len = matches.length; //don't make it inline
|
||||
for (let i = 0; i < len; i++) {
|
||||
let attrName = parser.processAttrName(matches[i][1]);
|
||||
let attrVal = parser.replaceEntities(matches[i][4] || true);
|
||||
|
||||
parser.outputBuilder.addAttribute(attrName, attrVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const getAllMatches = function(string, regex) {
|
||||
const matches = [];
|
||||
let match = regex.exec(string);
|
||||
while (match) {
|
||||
const allmatches = [];
|
||||
allmatches.startIndex = regex.lastIndex - match[0].length;
|
||||
const len = match.length;
|
||||
for (let index = 0; index < len; index++) {
|
||||
allmatches.push(match[index]);
|
||||
}
|
||||
matches.push(allmatches);
|
||||
match = regex.exec(string);
|
||||
}
|
||||
return matches;
|
||||
};
|
||||
|
111
em2rp/node_modules/fast-xml-parser/src/v6/XmlSpecialTagsReader.js
generated
vendored
Normal file
111
em2rp/node_modules/fast-xml-parser/src/v6/XmlSpecialTagsReader.js
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
import {readPiExp} from './XmlPartReader.js';
|
||||
|
||||
export function readCdata(parser){
|
||||
//<![ are already read till this point
|
||||
let str = parser.source.readStr(6); //CDATA[
|
||||
parser.source.updateBufferBoundary(6);
|
||||
|
||||
if(str !== "CDATA[") throw new Error(`Invalid CDATA expression at ${parser.source.line}:${parser.source.cols}`);
|
||||
|
||||
let text = parser.source.readUpto("]]>");
|
||||
parser.outputBuilder.addCdata(text);
|
||||
}
|
||||
export function readPiTag(parser){
|
||||
//<? are already read till this point
|
||||
let tagExp = readPiExp(parser, "?>");
|
||||
if(!tagExp) throw new Error("Invalid Pi Tag expression.");
|
||||
|
||||
if (tagExp.tagName === "?xml") {//TODO: test if tagName is just xml
|
||||
parser.outputBuilder.addDeclaration();
|
||||
} else {
|
||||
parser.outputBuilder.addPi("?"+tagExp.tagName);
|
||||
}
|
||||
}
|
||||
|
||||
export function readComment(parser){
|
||||
//<!- are already read till this point
|
||||
let ch = parser.source.readCh();
|
||||
if(ch !== "-") throw new Error(`Invalid comment expression at ${parser.source.line}:${parser.source.cols}`);
|
||||
|
||||
let text = parser.source.readUpto("-->");
|
||||
parser.outputBuilder.addComment(text);
|
||||
}
|
||||
|
||||
const DOCTYPE_tags = {
|
||||
"EL":/^EMENT\s+([^\s>]+)\s+(ANY|EMPTY|\(.+\)\s*$)/m,
|
||||
"AT":/^TLIST\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+$/m,
|
||||
"NO":/^TATION.+$/m
|
||||
}
|
||||
export function readDocType(parser){
|
||||
//<!D are already read till this point
|
||||
let str = parser.source.readStr(6); //OCTYPE
|
||||
parser.source.updateBufferBoundary(6);
|
||||
|
||||
if(str !== "OCTYPE") throw new Error(`Invalid DOCTYPE expression at ${parser.source.line}:${parser.source.cols}`);
|
||||
|
||||
let hasBody = false, lastch = "";
|
||||
|
||||
while(parser.source.canRead()){
|
||||
//TODO: use readChAt like used in partReader
|
||||
let ch = parser.source.readCh();
|
||||
if(hasBody){
|
||||
if (ch === '<') { //Determine the tag type
|
||||
let str = parser.source.readStr(2);
|
||||
parser.source.updateBufferBoundary(2);
|
||||
if(str === "EN"){ //ENTITY
|
||||
let str = parser.source.readStr(4);
|
||||
parser.source.updateBufferBoundary(4);
|
||||
if(str !== "TITY") throw new Error("Invalid DOCTYPE ENTITY expression");
|
||||
|
||||
registerEntity(parser);
|
||||
}else if(str === "!-") {//comment
|
||||
readComment(parser);
|
||||
}else{ //ELEMENT, ATTLIST, NOTATION
|
||||
let dTagExp = parser.source.readUpto(">");
|
||||
const regx = DOCTYPE_tags[str];
|
||||
if(regx){
|
||||
const match = dTagExp.match(regx);
|
||||
if(!match) throw new Error("Invalid DOCTYPE");
|
||||
}else throw new Error("Invalid DOCTYPE");
|
||||
}
|
||||
}else if( ch === '>' && lastch === "]"){//end of doctype
|
||||
return;
|
||||
}
|
||||
}else if( ch === '>'){//end of doctype
|
||||
return;
|
||||
}else if( ch === '['){
|
||||
hasBody = true;
|
||||
}else{
|
||||
lastch = ch;
|
||||
}
|
||||
}//End While loop
|
||||
|
||||
}
|
||||
|
||||
function registerEntity(parser){
|
||||
//read Entity
|
||||
let attrBoundary="";
|
||||
let name ="", val ="";
|
||||
while(source.canRead()){
|
||||
let ch = source.readCh();
|
||||
|
||||
if(attrBoundary){
|
||||
if (ch === attrBoundary){
|
||||
val = text;
|
||||
text = ""
|
||||
}
|
||||
}else if(ch === " " || ch === "\t"){
|
||||
if(!name){
|
||||
name = text.trimStart();
|
||||
text = "";
|
||||
}
|
||||
}else if (ch === '"' || ch === "'") {//start of attrBoundary
|
||||
attrBoundary = ch;
|
||||
}else if(ch === ">"){
|
||||
parser.entityParser.addExternalEntity(name,val);
|
||||
return;
|
||||
}else{
|
||||
text+=ch;
|
||||
}
|
||||
}
|
||||
}
|
116
em2rp/node_modules/fast-xml-parser/src/v6/inputSource/BufferSource.js
generated
vendored
Normal file
116
em2rp/node_modules/fast-xml-parser/src/v6/inputSource/BufferSource.js
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
const Constants = {
|
||||
space: 32,
|
||||
tab: 9
|
||||
}
|
||||
export default class BufferSource{
|
||||
constructor(bytesArr){
|
||||
this.line = 1;
|
||||
this.cols = 0;
|
||||
this.buffer = bytesArr;
|
||||
this.startIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
readCh() {
|
||||
return String.fromCharCode(this.buffer[this.startIndex++]);
|
||||
}
|
||||
|
||||
readChAt(index) {
|
||||
return String.fromCharCode(this.buffer[this.startIndex+index]);
|
||||
}
|
||||
|
||||
readStr(n,from){
|
||||
if(typeof from === "undefined") from = this.startIndex;
|
||||
return this.buffer.slice(from, from + n).toString();
|
||||
}
|
||||
|
||||
readUpto(stopStr) {
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
const stopBuffer = Buffer.from(stopStr);
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
let match = true;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopBuffer[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
const result = this.buffer.slice(this.startIndex, i).toString();
|
||||
this.startIndex = i + stopLength;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readUptoCloseTag(stopStr) { //stopStr: "</tagname"
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
const stopBuffer = Buffer.from(stopStr);
|
||||
let stopIndex = 0;
|
||||
//0: non-matching, 1: matching stop string, 2: matching closing
|
||||
let match = 0;
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
if(match === 1){//initial part matched
|
||||
if(stopIndex === 0) stopIndex = i;
|
||||
if(this.buffer[i] === Constants.space || this.buffer[i] === Constants.tab) continue;
|
||||
else if(this.buffer[i] === '>'){ //TODO: if it should be equivalent ASCII
|
||||
match = 2;
|
||||
//tag boundary found
|
||||
// this.startIndex
|
||||
}
|
||||
}else{
|
||||
match = 1;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopBuffer[j]) {
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match === 2) {//matched closing part
|
||||
const result = this.buffer.slice(this.startIndex, stopIndex - 1 ).toString();
|
||||
this.startIndex = i + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readFromBuffer(n, shouldUpdate) {
|
||||
let ch;
|
||||
if (n === 1) {
|
||||
ch = this.buffer[this.startIndex];
|
||||
if (ch === 10) {
|
||||
this.line++;
|
||||
this.cols = 1;
|
||||
} else {
|
||||
this.cols++;
|
||||
}
|
||||
ch = String.fromCharCode(ch);
|
||||
} else {
|
||||
this.cols += n;
|
||||
ch = this.buffer.slice(this.startIndex, this.startIndex + n).toString();
|
||||
}
|
||||
if (shouldUpdate) this.updateBuffer(n);
|
||||
return ch;
|
||||
}
|
||||
|
||||
updateBufferBoundary(n = 1) { //n: number of characters read
|
||||
this.startIndex += n;
|
||||
}
|
||||
|
||||
canRead(n){
|
||||
n = n || this.startIndex;
|
||||
return this.buffer.length - n + 1 > 0;
|
||||
}
|
||||
|
||||
}
|
121
em2rp/node_modules/fast-xml-parser/src/v6/inputSource/StringSource.js
generated
vendored
Normal file
121
em2rp/node_modules/fast-xml-parser/src/v6/inputSource/StringSource.js
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
const whiteSpaces = [" ", "\n", "\t"];
|
||||
|
||||
|
||||
export default class StringSource{
|
||||
constructor(str){
|
||||
this.line = 1;
|
||||
this.cols = 0;
|
||||
this.buffer = str;
|
||||
//a boundary pointer to indicate where from the buffer dat should be read
|
||||
// data before this pointer can be deleted to free the memory
|
||||
this.startIndex = 0;
|
||||
}
|
||||
|
||||
readCh() {
|
||||
return this.buffer[this.startIndex++];
|
||||
}
|
||||
|
||||
readChAt(index) {
|
||||
return this.buffer[this.startIndex+index];
|
||||
}
|
||||
|
||||
readStr(n,from){
|
||||
if(typeof from === "undefined") from = this.startIndex;
|
||||
return this.buffer.substring(from, from + n);
|
||||
}
|
||||
|
||||
readUpto(stopStr) {
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
let match = true;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopStr[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
const result = this.buffer.substring(this.startIndex, i);
|
||||
this.startIndex = i + stopLength;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readUptoCloseTag(stopStr) { //stopStr: "</tagname"
|
||||
const inputLength = this.buffer.length;
|
||||
const stopLength = stopStr.length;
|
||||
let stopIndex = 0;
|
||||
//0: non-matching, 1: matching stop string, 2: matching closing
|
||||
let match = 0;
|
||||
|
||||
for (let i = this.startIndex; i < inputLength; i++) {
|
||||
if(match === 1){//initial part matched
|
||||
if(stopIndex === 0) stopIndex = i;
|
||||
if(this.buffer[i] === ' ' || this.buffer[i] === '\t') continue;
|
||||
else if(this.buffer[i] === '>'){
|
||||
match = 2;
|
||||
//tag boundary found
|
||||
// this.startIndex
|
||||
}
|
||||
}else{
|
||||
match = 1;
|
||||
for (let j = 0; j < stopLength; j++) {
|
||||
if (this.buffer[i + j] !== stopStr[j]) {
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match === 2) {//matched closing part
|
||||
const result = this.buffer.substring(this.startIndex, stopIndex - 1 );
|
||||
this.startIndex = i + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected end of source. Reading '${stopStr}'`);
|
||||
}
|
||||
|
||||
readFromBuffer(n, updateIndex){
|
||||
let ch;
|
||||
if(n===1){
|
||||
ch = this.buffer[this.startIndex];
|
||||
// if(ch === "\n") {
|
||||
// this.line++;
|
||||
// this.cols = 1;
|
||||
// }else{
|
||||
// this.cols++;
|
||||
// }
|
||||
}else{
|
||||
ch = this.buffer.substring(this.startIndex, this.startIndex + n);
|
||||
// if("".indexOf("\n") !== -1){
|
||||
// //TODO: handle the scenario when there are multiple lines
|
||||
// //TODO: col should be set to number of chars after last '\n'
|
||||
// // this.cols = 1;
|
||||
// }else{
|
||||
// this.cols += n;
|
||||
|
||||
// }
|
||||
}
|
||||
if(updateIndex) this.updateBufferBoundary(n);
|
||||
return ch;
|
||||
}
|
||||
|
||||
//TODO: rename to updateBufferReadIndex
|
||||
|
||||
updateBufferBoundary(n = 1) { //n: number of characters read
|
||||
this.startIndex += n;
|
||||
}
|
||||
|
||||
canRead(n){
|
||||
n = n || this.startIndex;
|
||||
return this.buffer.length - n + 1 > 0;
|
||||
}
|
||||
|
||||
}
|
105
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/EntitiesParser.js
generated
vendored
Normal file
105
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/EntitiesParser.js
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
const ampEntity = { regex: /&(amp|#38|#x26);/g, val : "&"};
|
||||
const htmlEntities = {
|
||||
"space": { regex: /&(nbsp|#160);/g, val: " " },
|
||||
// "lt" : { regex: /&(lt|#60);/g, val: "<" },
|
||||
// "gt" : { regex: /&(gt|#62);/g, val: ">" },
|
||||
// "amp" : { regex: /&(amp|#38);/g, val: "&" },
|
||||
// "quot" : { regex: /&(quot|#34);/g, val: "\"" },
|
||||
// "apos" : { regex: /&(apos|#39);/g, val: "'" },
|
||||
"cent" : { regex: /&(cent|#162);/g, val: "¢" },
|
||||
"pound" : { regex: /&(pound|#163);/g, val: "£" },
|
||||
"yen" : { regex: /&(yen|#165);/g, val: "¥" },
|
||||
"euro" : { regex: /&(euro|#8364);/g, val: "€" },
|
||||
"copyright" : { regex: /&(copy|#169);/g, val: "©" },
|
||||
"reg" : { regex: /&(reg|#174);/g, val: "®" },
|
||||
"inr" : { regex: /&(inr|#8377);/g, val: "₹" },
|
||||
"num_dec": { regex: /&#([0-9]{1,7});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 10)) },
|
||||
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 16)) },
|
||||
};
|
||||
|
||||
export default class EntitiesParser{
|
||||
constructor(replaceHtmlEntities) {
|
||||
this.replaceHtmlEntities = replaceHtmlEntities;
|
||||
this.docTypeEntities = {};
|
||||
this.lastEntities = {
|
||||
"apos" : { regex: /&(apos|#39|#x27);/g, val : "'"},
|
||||
"gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"},
|
||||
"lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"},
|
||||
"quot" : { regex: /&(quot|#34|#x22);/g, val : "\""},
|
||||
};
|
||||
}
|
||||
|
||||
addExternalEntities(externalEntities){
|
||||
const entKeys = Object.keys(externalEntities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.addExternalEntity(ent,externalEntities[ent])
|
||||
}
|
||||
}
|
||||
addExternalEntity(key,val){
|
||||
validateEntityName(key);
|
||||
if(val.indexOf("&") !== -1) {
|
||||
reportWarning(`Entity ${key} is not added as '&' is found in value;`)
|
||||
return;
|
||||
}else{
|
||||
this.lastEntities[ent] = {
|
||||
regex: new RegExp("&"+key+";","g"),
|
||||
val : val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDocTypeEntities(entities){
|
||||
const entKeys = Object.keys(entities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.docTypeEntities[ent] = {
|
||||
regex: new RegExp("&"+ent+";","g"),
|
||||
val : entities[ent]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parse(val){
|
||||
return this.replaceEntitiesValue(val)
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Replace DOCTYPE entities
|
||||
* 2. Replace external entities
|
||||
* 3. Replace HTML entities if asked
|
||||
* @param {string} val
|
||||
*/
|
||||
replaceEntitiesValue(val){
|
||||
if(typeof val === "string" && val.length > 0){
|
||||
for(let entityName in this.docTypeEntities){
|
||||
const entity = this.docTypeEntities[entityName];
|
||||
val = val.replace( entity.regx, entity.val);
|
||||
}
|
||||
for(let entityName in this.lastEntities){
|
||||
const entity = this.lastEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
if(this.replaceHtmlEntities){
|
||||
for(let entityName in htmlEntities){
|
||||
const entity = htmlEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
val = val.replace( ampEntity.regex, ampEntity.val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
//an entity name should not contains special characters that may be used in regex
|
||||
//Eg !?\\\/[]$%{}^&*()<>
|
||||
const specialChar = "!?\\\/[]$%{}^&*()<>|+";
|
||||
|
||||
function validateEntityName(name){
|
||||
for (let i = 0; i < specialChar.length; i++) {
|
||||
const ch = specialChar[i];
|
||||
if(name.indexOf(ch) !== -1) throw new Error(`Invalid character ${ch} in entity name`);
|
||||
}
|
||||
return name;
|
||||
}
|
22
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/booleanParser.js
generated
vendored
Normal file
22
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/booleanParser.js
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
export default class boolParser{
|
||||
constructor(trueList, falseList){
|
||||
if(trueList)
|
||||
this.trueList = trueList;
|
||||
else
|
||||
this.trueList = ["true"];
|
||||
|
||||
if(falseList)
|
||||
this.falseList = falseList;
|
||||
else
|
||||
this.falseList = ["false"];
|
||||
}
|
||||
parse(val){
|
||||
if (typeof val === 'string') {
|
||||
//TODO: performance: don't convert
|
||||
const temp = val.toLowerCase();
|
||||
if(this.trueList.indexOf(temp) !== -1) return true;
|
||||
else if(this.falseList.indexOf(temp) !== -1 ) return false;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
19
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/booleanParserExt.js
generated
vendored
Normal file
19
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/booleanParserExt.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
export default function boolParserExt(val){
|
||||
if(isArray(val)){
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
val[i] = parse(val[i])
|
||||
}
|
||||
}else{
|
||||
val = parse(val)
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
function parse(val){
|
||||
if (typeof val === 'string') {
|
||||
const temp = val.toLowerCase();
|
||||
if(temp === 'true' || temp ==="yes" || temp==="1") return true;
|
||||
else if(temp === 'false' || temp ==="no" || temp==="0") return false;
|
||||
}
|
||||
return val;
|
||||
}
|
38
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/currency.js
generated
vendored
Normal file
38
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/currency.js
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
const defaultOptions = {
|
||||
maxLength: 200,
|
||||
// locale: "en-IN"
|
||||
}
|
||||
const localeMap = {
|
||||
"$":"en-US",
|
||||
"€":"de-DE",
|
||||
"£":"en-GB",
|
||||
"¥":"ja-JP",
|
||||
"₹":"en-IN",
|
||||
}
|
||||
const sign = "(?:-|\+)?";
|
||||
const digitsAndSeparator = "(?:\d+|\d{1,3}(?:,\d{3})+)";
|
||||
const decimalPart = "(?:\.\d{1,2})?";
|
||||
const symbol = "(?:\$|€|¥|₹)?";
|
||||
|
||||
const currencyCheckRegex = /^\s*(?:-|\+)?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d{1,2})?\s*(?:\$|€|¥|₹)?\s*$/u;
|
||||
|
||||
export default class CurrencyParser{
|
||||
constructor(options){
|
||||
this.options = options || defaultOptions;
|
||||
}
|
||||
parse(val){
|
||||
if (typeof val === 'string' && val.length <= this.options.maxLength) {
|
||||
if(val.indexOf(",,") !== -1 && val.indexOf(".." !== -1)){
|
||||
const match = val.match(currencyCheckRegex);
|
||||
if(match){
|
||||
const locale = this.options.locale || localeMap[match[2]||match[5]||"₹"];
|
||||
const formatter = new Intl.NumberFormat(locale)
|
||||
val = val.replace(/[^0-9,.]/g, '').trim();
|
||||
val = Number(val.replace(formatter.format(1000)[1], ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
CurrencyParser.defaultOptions = defaultOptions;
|
13
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/join.js
generated
vendored
Normal file
13
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/join.js
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
*
|
||||
* @param {array} val
|
||||
* @param {string} by
|
||||
* @returns
|
||||
*/
|
||||
export default function join(val, by=" "){
|
||||
if(isArray(val)){
|
||||
val.join(by)
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
14
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/number.js
generated
vendored
Normal file
14
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/number.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import toNumber from "strnum";
|
||||
|
||||
|
||||
export default class numParser{
|
||||
constructor(options){
|
||||
this.options = options;
|
||||
}
|
||||
parse(val){
|
||||
if (typeof val === 'string') {
|
||||
val = toNumber(val,this.options);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
6
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/trim.js
generated
vendored
Normal file
6
em2rp/node_modules/fast-xml-parser/src/v6/valueParsers/trim.js
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export default class trimmer{
|
||||
parse(val){
|
||||
if(typeof val === "string") return val.trim();
|
||||
else return val;
|
||||
}
|
||||
}
|
425
em2rp/node_modules/fast-xml-parser/src/validator.js
generated
vendored
Normal file
425
em2rp/node_modules/fast-xml-parser/src/validator.js
generated
vendored
Normal file
@ -0,0 +1,425 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('./util');
|
||||
|
||||
const defaultOptions = {
|
||||
allowBooleanAttributes: false, //A tag can have attributes without any value
|
||||
unpairedTags: []
|
||||
};
|
||||
|
||||
//const tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g");
|
||||
exports.validate = function (xmlData, options) {
|
||||
options = Object.assign({}, defaultOptions, options);
|
||||
|
||||
//xmlData = xmlData.replace(/(\r\n|\n|\r)/gm,"");//make it single line
|
||||
//xmlData = xmlData.replace(/(^\s*<\?xml.*?\?>)/g,"");//Remove XML starting tag
|
||||
//xmlData = xmlData.replace(/(<!DOCTYPE[\s\w\"\.\/\-\:]+(\[.*\])*\s*>)/g,"");//Remove DOCTYPE
|
||||
const tags = [];
|
||||
let tagFound = false;
|
||||
|
||||
//indicates that the root tag has been closed (aka. depth 0 has been reached)
|
||||
let reachedRoot = false;
|
||||
|
||||
if (xmlData[0] === '\ufeff') {
|
||||
// check for byte order mark (BOM)
|
||||
xmlData = xmlData.substr(1);
|
||||
}
|
||||
|
||||
for (let i = 0; i < xmlData.length; i++) {
|
||||
|
||||
if (xmlData[i] === '<' && xmlData[i+1] === '?') {
|
||||
i+=2;
|
||||
i = readPI(xmlData,i);
|
||||
if (i.err) return i;
|
||||
}else if (xmlData[i] === '<') {
|
||||
//starting of tag
|
||||
//read until you reach to '>' avoiding any '>' in attribute value
|
||||
let tagStartPos = i;
|
||||
i++;
|
||||
|
||||
if (xmlData[i] === '!') {
|
||||
i = readCommentAndCDATA(xmlData, i);
|
||||
continue;
|
||||
} else {
|
||||
let closingTag = false;
|
||||
if (xmlData[i] === '/') {
|
||||
//closing tag
|
||||
closingTag = true;
|
||||
i++;
|
||||
}
|
||||
//read tagname
|
||||
let tagName = '';
|
||||
for (; i < xmlData.length &&
|
||||
xmlData[i] !== '>' &&
|
||||
xmlData[i] !== ' ' &&
|
||||
xmlData[i] !== '\t' &&
|
||||
xmlData[i] !== '\n' &&
|
||||
xmlData[i] !== '\r'; i++
|
||||
) {
|
||||
tagName += xmlData[i];
|
||||
}
|
||||
tagName = tagName.trim();
|
||||
//console.log(tagName);
|
||||
|
||||
if (tagName[tagName.length - 1] === '/') {
|
||||
//self closing tag without attributes
|
||||
tagName = tagName.substring(0, tagName.length - 1);
|
||||
//continue;
|
||||
i--;
|
||||
}
|
||||
if (!validateTagName(tagName)) {
|
||||
let msg;
|
||||
if (tagName.trim().length === 0) {
|
||||
msg = "Invalid space after '<'.";
|
||||
} else {
|
||||
msg = "Tag '"+tagName+"' is an invalid name.";
|
||||
}
|
||||
return getErrorObject('InvalidTag', msg, getLineNumberForPosition(xmlData, i));
|
||||
}
|
||||
|
||||
const result = readAttributeStr(xmlData, i);
|
||||
if (result === false) {
|
||||
return getErrorObject('InvalidAttr', "Attributes for '"+tagName+"' have open quote.", getLineNumberForPosition(xmlData, i));
|
||||
}
|
||||
let attrStr = result.value;
|
||||
i = result.index;
|
||||
|
||||
if (attrStr[attrStr.length - 1] === '/') {
|
||||
//self closing tag
|
||||
const attrStrStart = i - attrStr.length;
|
||||
attrStr = attrStr.substring(0, attrStr.length - 1);
|
||||
const isValid = validateAttributeString(attrStr, options);
|
||||
if (isValid === true) {
|
||||
tagFound = true;
|
||||
//continue; //text may presents after self closing tag
|
||||
} else {
|
||||
//the result from the nested function returns the position of the error within the attribute
|
||||
//in order to get the 'true' error line, we need to calculate the position where the attribute begins (i - attrStr.length) and then add the position within the attribute
|
||||
//this gives us the absolute index in the entire xml, which we can use to find the line at last
|
||||
return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line));
|
||||
}
|
||||
} else if (closingTag) {
|
||||
if (!result.tagClosed) {
|
||||
return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' doesn't have proper closing.", getLineNumberForPosition(xmlData, i));
|
||||
} else if (attrStr.trim().length > 0) {
|
||||
return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos));
|
||||
} else if (tags.length === 0) {
|
||||
return getErrorObject('InvalidTag', "Closing tag '"+tagName+"' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos));
|
||||
} else {
|
||||
const otg = tags.pop();
|
||||
if (tagName !== otg.tagName) {
|
||||
let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos);
|
||||
return getErrorObject('InvalidTag',
|
||||
"Expected closing tag '"+otg.tagName+"' (opened in line "+openPos.line+", col "+openPos.col+") instead of closing tag '"+tagName+"'.",
|
||||
getLineNumberForPosition(xmlData, tagStartPos));
|
||||
}
|
||||
|
||||
//when there are no more tags, we reached the root level.
|
||||
if (tags.length == 0) {
|
||||
reachedRoot = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const isValid = validateAttributeString(attrStr, options);
|
||||
if (isValid !== true) {
|
||||
//the result from the nested function returns the position of the error within the attribute
|
||||
//in order to get the 'true' error line, we need to calculate the position where the attribute begins (i - attrStr.length) and then add the position within the attribute
|
||||
//this gives us the absolute index in the entire xml, which we can use to find the line at last
|
||||
return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line));
|
||||
}
|
||||
|
||||
//if the root level has been reached before ...
|
||||
if (reachedRoot === true) {
|
||||
return getErrorObject('InvalidXml', 'Multiple possible root nodes found.', getLineNumberForPosition(xmlData, i));
|
||||
} else if(options.unpairedTags.indexOf(tagName) !== -1){
|
||||
//don't push into stack
|
||||
} else {
|
||||
tags.push({tagName, tagStartPos});
|
||||
}
|
||||
tagFound = true;
|
||||
}
|
||||
|
||||
//skip tag text value
|
||||
//It may include comments and CDATA value
|
||||
for (i++; i < xmlData.length; i++) {
|
||||
if (xmlData[i] === '<') {
|
||||
if (xmlData[i + 1] === '!') {
|
||||
//comment or CADATA
|
||||
i++;
|
||||
i = readCommentAndCDATA(xmlData, i);
|
||||
continue;
|
||||
} else if (xmlData[i+1] === '?') {
|
||||
i = readPI(xmlData, ++i);
|
||||
if (i.err) return i;
|
||||
} else{
|
||||
break;
|
||||
}
|
||||
} else if (xmlData[i] === '&') {
|
||||
const afterAmp = validateAmpersand(xmlData, i);
|
||||
if (afterAmp == -1)
|
||||
return getErrorObject('InvalidChar', "char '&' is not expected.", getLineNumberForPosition(xmlData, i));
|
||||
i = afterAmp;
|
||||
}else{
|
||||
if (reachedRoot === true && !isWhiteSpace(xmlData[i])) {
|
||||
return getErrorObject('InvalidXml', "Extra text at the end", getLineNumberForPosition(xmlData, i));
|
||||
}
|
||||
}
|
||||
} //end of reading tag text value
|
||||
if (xmlData[i] === '<') {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( isWhiteSpace(xmlData[i])) {
|
||||
continue;
|
||||
}
|
||||
return getErrorObject('InvalidChar', "char '"+xmlData[i]+"' is not expected.", getLineNumberForPosition(xmlData, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (!tagFound) {
|
||||
return getErrorObject('InvalidXml', 'Start tag expected.', 1);
|
||||
}else if (tags.length == 1) {
|
||||
return getErrorObject('InvalidTag', "Unclosed tag '"+tags[0].tagName+"'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos));
|
||||
}else if (tags.length > 0) {
|
||||
return getErrorObject('InvalidXml', "Invalid '"+
|
||||
JSON.stringify(tags.map(t => t.tagName), null, 4).replace(/\r?\n/g, '')+
|
||||
"' found.", {line: 1, col: 1});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
function isWhiteSpace(char){
|
||||
return char === ' ' || char === '\t' || char === '\n' || char === '\r';
|
||||
}
|
||||
/**
|
||||
* Read Processing insstructions and skip
|
||||
* @param {*} xmlData
|
||||
* @param {*} i
|
||||
*/
|
||||
function readPI(xmlData, i) {
|
||||
const start = i;
|
||||
for (; i < xmlData.length; i++) {
|
||||
if (xmlData[i] == '?' || xmlData[i] == ' ') {
|
||||
//tagname
|
||||
const tagname = xmlData.substr(start, i - start);
|
||||
if (i > 5 && tagname === 'xml') {
|
||||
return getErrorObject('InvalidXml', 'XML declaration allowed only at the start of the document.', getLineNumberForPosition(xmlData, i));
|
||||
} else if (xmlData[i] == '?' && xmlData[i + 1] == '>') {
|
||||
//check if valid attribut string
|
||||
i++;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
function readCommentAndCDATA(xmlData, i) {
|
||||
if (xmlData.length > i + 5 && xmlData[i + 1] === '-' && xmlData[i + 2] === '-') {
|
||||
//comment
|
||||
for (i += 3; i < xmlData.length; i++) {
|
||||
if (xmlData[i] === '-' && xmlData[i + 1] === '-' && xmlData[i + 2] === '>') {
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
xmlData.length > i + 8 &&
|
||||
xmlData[i + 1] === 'D' &&
|
||||
xmlData[i + 2] === 'O' &&
|
||||
xmlData[i + 3] === 'C' &&
|
||||
xmlData[i + 4] === 'T' &&
|
||||
xmlData[i + 5] === 'Y' &&
|
||||
xmlData[i + 6] === 'P' &&
|
||||
xmlData[i + 7] === 'E'
|
||||
) {
|
||||
let angleBracketsCount = 1;
|
||||
for (i += 8; i < xmlData.length; i++) {
|
||||
if (xmlData[i] === '<') {
|
||||
angleBracketsCount++;
|
||||
} else if (xmlData[i] === '>') {
|
||||
angleBracketsCount--;
|
||||
if (angleBracketsCount === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
xmlData.length > i + 9 &&
|
||||
xmlData[i + 1] === '[' &&
|
||||
xmlData[i + 2] === 'C' &&
|
||||
xmlData[i + 3] === 'D' &&
|
||||
xmlData[i + 4] === 'A' &&
|
||||
xmlData[i + 5] === 'T' &&
|
||||
xmlData[i + 6] === 'A' &&
|
||||
xmlData[i + 7] === '['
|
||||
) {
|
||||
for (i += 8; i < xmlData.length; i++) {
|
||||
if (xmlData[i] === ']' && xmlData[i + 1] === ']' && xmlData[i + 2] === '>') {
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
const doubleQuote = '"';
|
||||
const singleQuote = "'";
|
||||
|
||||
/**
|
||||
* Keep reading xmlData until '<' is found outside the attribute value.
|
||||
* @param {string} xmlData
|
||||
* @param {number} i
|
||||
*/
|
||||
function readAttributeStr(xmlData, i) {
|
||||
let attrStr = '';
|
||||
let startChar = '';
|
||||
let tagClosed = false;
|
||||
for (; i < xmlData.length; i++) {
|
||||
if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) {
|
||||
if (startChar === '') {
|
||||
startChar = xmlData[i];
|
||||
} else if (startChar !== xmlData[i]) {
|
||||
//if vaue is enclosed with double quote then single quotes are allowed inside the value and vice versa
|
||||
} else {
|
||||
startChar = '';
|
||||
}
|
||||
} else if (xmlData[i] === '>') {
|
||||
if (startChar === '') {
|
||||
tagClosed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
attrStr += xmlData[i];
|
||||
}
|
||||
if (startChar !== '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
value: attrStr,
|
||||
index: i,
|
||||
tagClosed: tagClosed
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all the attributes whether valid or invalid.
|
||||
*/
|
||||
const validAttrStrRegxp = new RegExp('(\\s*)([^\\s=]+)(\\s*=)?(\\s*([\'"])(([\\s\\S])*?)\\5)?', 'g');
|
||||
|
||||
//attr, ="sd", a="amit's", a="sd"b="saf", ab cd=""
|
||||
|
||||
function validateAttributeString(attrStr, options) {
|
||||
//console.log("start:"+attrStr+":end");
|
||||
|
||||
//if(attrStr.trim().length === 0) return true; //empty string
|
||||
|
||||
const matches = util.getAllMatches(attrStr, validAttrStrRegxp);
|
||||
const attrNames = {};
|
||||
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
if (matches[i][1].length === 0) {
|
||||
//nospace before attribute name: a="sd"b="saf"
|
||||
return getErrorObject('InvalidAttr', "Attribute '"+matches[i][2]+"' has no space in starting.", getPositionFromMatch(matches[i]))
|
||||
} else if (matches[i][3] !== undefined && matches[i][4] === undefined) {
|
||||
return getErrorObject('InvalidAttr', "Attribute '"+matches[i][2]+"' is without value.", getPositionFromMatch(matches[i]));
|
||||
} else if (matches[i][3] === undefined && !options.allowBooleanAttributes) {
|
||||
//independent attribute: ab
|
||||
return getErrorObject('InvalidAttr', "boolean attribute '"+matches[i][2]+"' is not allowed.", getPositionFromMatch(matches[i]));
|
||||
}
|
||||
/* else if(matches[i][6] === undefined){//attribute without value: ab=
|
||||
return { err: { code:"InvalidAttr",msg:"attribute " + matches[i][2] + " has no value assigned."}};
|
||||
} */
|
||||
const attrName = matches[i][2];
|
||||
if (!validateAttrName(attrName)) {
|
||||
return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is an invalid name.", getPositionFromMatch(matches[i]));
|
||||
}
|
||||
if (!attrNames.hasOwnProperty(attrName)) {
|
||||
//check for duplicate attribute.
|
||||
attrNames[attrName] = 1;
|
||||
} else {
|
||||
return getErrorObject('InvalidAttr', "Attribute '"+attrName+"' is repeated.", getPositionFromMatch(matches[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateNumberAmpersand(xmlData, i) {
|
||||
let re = /\d/;
|
||||
if (xmlData[i] === 'x') {
|
||||
i++;
|
||||
re = /[\da-fA-F]/;
|
||||
}
|
||||
for (; i < xmlData.length; i++) {
|
||||
if (xmlData[i] === ';')
|
||||
return i;
|
||||
if (!xmlData[i].match(re))
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function validateAmpersand(xmlData, i) {
|
||||
// https://www.w3.org/TR/xml/#dt-charref
|
||||
i++;
|
||||
if (xmlData[i] === ';')
|
||||
return -1;
|
||||
if (xmlData[i] === '#') {
|
||||
i++;
|
||||
return validateNumberAmpersand(xmlData, i);
|
||||
}
|
||||
let count = 0;
|
||||
for (; i < xmlData.length; i++, count++) {
|
||||
if (xmlData[i].match(/\w/) && count < 20)
|
||||
continue;
|
||||
if (xmlData[i] === ';')
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
function getErrorObject(code, message, lineNumber) {
|
||||
return {
|
||||
err: {
|
||||
code: code,
|
||||
msg: message,
|
||||
line: lineNumber.line || lineNumber,
|
||||
col: lineNumber.col,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function validateAttrName(attrName) {
|
||||
return util.isName(attrName);
|
||||
}
|
||||
|
||||
// const startsWithXML = /^xml/i;
|
||||
|
||||
function validateTagName(tagname) {
|
||||
return util.isName(tagname) /* && !tagname.match(startsWithXML) */;
|
||||
}
|
||||
|
||||
//this function returns the line number for the character at the given index
|
||||
function getLineNumberForPosition(xmlData, index) {
|
||||
const lines = xmlData.substring(0, index).split(/\r?\n/);
|
||||
return {
|
||||
line: lines.length,
|
||||
|
||||
// column number is last line's length + 1, because column numbering starts at 1:
|
||||
col: lines[lines.length - 1].length + 1
|
||||
};
|
||||
}
|
||||
|
||||
//this function returns the position of the first character of match within attrStr
|
||||
function getPositionFromMatch(match) {
|
||||
return match.startIndex + match[1].length;
|
||||
}
|
286
em2rp/node_modules/fast-xml-parser/src/xmlbuilder/json2xml.js
generated
vendored
Normal file
286
em2rp/node_modules/fast-xml-parser/src/xmlbuilder/json2xml.js
generated
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
'use strict';
|
||||
//parse Empty Node as self closing node
|
||||
const buildFromOrderedJs = require('./orderedJs2Xml');
|
||||
const getIgnoreAttributesFn = require('../ignoreAttributes')
|
||||
|
||||
const defaultOptions = {
|
||||
attributeNamePrefix: '@_',
|
||||
attributesGroupName: false,
|
||||
textNodeName: '#text',
|
||||
ignoreAttributes: true,
|
||||
cdataPropName: false,
|
||||
format: false,
|
||||
indentBy: ' ',
|
||||
suppressEmptyNode: false,
|
||||
suppressUnpairedNode: true,
|
||||
suppressBooleanAttributes: true,
|
||||
tagValueProcessor: function(key, a) {
|
||||
return a;
|
||||
},
|
||||
attributeValueProcessor: function(attrName, a) {
|
||||
return a;
|
||||
},
|
||||
preserveOrder: false,
|
||||
commentPropName: false,
|
||||
unpairedTags: [],
|
||||
entities: [
|
||||
{ regex: new RegExp("&", "g"), val: "&" },//it must be on top
|
||||
{ regex: new RegExp(">", "g"), val: ">" },
|
||||
{ regex: new RegExp("<", "g"), val: "<" },
|
||||
{ regex: new RegExp("\'", "g"), val: "'" },
|
||||
{ regex: new RegExp("\"", "g"), val: """ }
|
||||
],
|
||||
processEntities: true,
|
||||
stopNodes: [],
|
||||
// transformTagName: false,
|
||||
// transformAttributeName: false,
|
||||
oneListGroup: false
|
||||
};
|
||||
|
||||
function Builder(options) {
|
||||
this.options = Object.assign({}, defaultOptions, options);
|
||||
if (this.options.ignoreAttributes === true || this.options.attributesGroupName) {
|
||||
this.isAttribute = function(/*a*/) {
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes)
|
||||
this.attrPrefixLen = this.options.attributeNamePrefix.length;
|
||||
this.isAttribute = isAttribute;
|
||||
}
|
||||
|
||||
this.processTextOrObjNode = processTextOrObjNode
|
||||
|
||||
if (this.options.format) {
|
||||
this.indentate = indentate;
|
||||
this.tagEndChar = '>\n';
|
||||
this.newLine = '\n';
|
||||
} else {
|
||||
this.indentate = function() {
|
||||
return '';
|
||||
};
|
||||
this.tagEndChar = '>';
|
||||
this.newLine = '';
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.build = function(jObj) {
|
||||
if(this.options.preserveOrder){
|
||||
return buildFromOrderedJs(jObj, this.options);
|
||||
}else {
|
||||
if(Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1){
|
||||
jObj = {
|
||||
[this.options.arrayNodeName] : jObj
|
||||
}
|
||||
}
|
||||
return this.j2x(jObj, 0, []).val;
|
||||
}
|
||||
};
|
||||
|
||||
Builder.prototype.j2x = function(jObj, level, ajPath) {
|
||||
let attrStr = '';
|
||||
let val = '';
|
||||
const jPath = ajPath.join('.')
|
||||
for (let key in jObj) {
|
||||
if(!Object.prototype.hasOwnProperty.call(jObj, key)) continue;
|
||||
if (typeof jObj[key] === 'undefined') {
|
||||
// supress undefined node only if it is not an attribute
|
||||
if (this.isAttribute(key)) {
|
||||
val += '';
|
||||
}
|
||||
} else if (jObj[key] === null) {
|
||||
// null attribute should be ignored by the attribute list, but should not cause the tag closing
|
||||
if (this.isAttribute(key)) {
|
||||
val += '';
|
||||
} else if (key === this.options.cdataPropName) {
|
||||
val += '';
|
||||
} else if (key[0] === '?') {
|
||||
val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
|
||||
} else {
|
||||
val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
}
|
||||
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
} else if (jObj[key] instanceof Date) {
|
||||
val += this.buildTextValNode(jObj[key], key, '', level);
|
||||
} else if (typeof jObj[key] !== 'object') {
|
||||
//premitive type
|
||||
const attr = this.isAttribute(key);
|
||||
if (attr && !this.ignoreAttributesFn(attr, jPath)) {
|
||||
attrStr += this.buildAttrPairStr(attr, '' + jObj[key]);
|
||||
} else if (!attr) {
|
||||
//tag value
|
||||
if (key === this.options.textNodeName) {
|
||||
let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
|
||||
val += this.replaceEntitiesValue(newval);
|
||||
} else {
|
||||
val += this.buildTextValNode(jObj[key], key, '', level);
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(jObj[key])) {
|
||||
//repeated nodes
|
||||
const arrLen = jObj[key].length;
|
||||
let listTagVal = "";
|
||||
let listTagAttr = "";
|
||||
for (let j = 0; j < arrLen; j++) {
|
||||
const item = jObj[key][j];
|
||||
if (typeof item === 'undefined') {
|
||||
// supress undefined node
|
||||
} else if (item === null) {
|
||||
if(key[0] === "?") val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
|
||||
else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
} else if (typeof item === 'object') {
|
||||
if(this.options.oneListGroup){
|
||||
const result = this.j2x(item, level + 1, ajPath.concat(key));
|
||||
listTagVal += result.val;
|
||||
if (this.options.attributesGroupName && item.hasOwnProperty(this.options.attributesGroupName)) {
|
||||
listTagAttr += result.attrStr
|
||||
}
|
||||
}else{
|
||||
listTagVal += this.processTextOrObjNode(item, key, level, ajPath)
|
||||
}
|
||||
} else {
|
||||
if (this.options.oneListGroup) {
|
||||
let textValue = this.options.tagValueProcessor(key, item);
|
||||
textValue = this.replaceEntitiesValue(textValue);
|
||||
listTagVal += textValue;
|
||||
} else {
|
||||
listTagVal += this.buildTextValNode(item, key, '', level);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.options.oneListGroup){
|
||||
listTagVal = this.buildObjectNode(listTagVal, key, listTagAttr, level);
|
||||
}
|
||||
val += listTagVal;
|
||||
} else {
|
||||
//nested node
|
||||
if (this.options.attributesGroupName && key === this.options.attributesGroupName) {
|
||||
const Ks = Object.keys(jObj[key]);
|
||||
const L = Ks.length;
|
||||
for (let j = 0; j < L; j++) {
|
||||
attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]]);
|
||||
}
|
||||
} else {
|
||||
val += this.processTextOrObjNode(jObj[key], key, level, ajPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return {attrStr: attrStr, val: val};
|
||||
};
|
||||
|
||||
Builder.prototype.buildAttrPairStr = function(attrName, val){
|
||||
val = this.options.attributeValueProcessor(attrName, '' + val);
|
||||
val = this.replaceEntitiesValue(val);
|
||||
if (this.options.suppressBooleanAttributes && val === "true") {
|
||||
return ' ' + attrName;
|
||||
} else return ' ' + attrName + '="' + val + '"';
|
||||
}
|
||||
|
||||
function processTextOrObjNode (object, key, level, ajPath) {
|
||||
const result = this.j2x(object, level + 1, ajPath.concat(key));
|
||||
if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
|
||||
return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level);
|
||||
} else {
|
||||
return this.buildObjectNode(result.val, key, result.attrStr, level);
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.buildObjectNode = function(val, key, attrStr, level) {
|
||||
if(val === ""){
|
||||
if(key[0] === "?") return this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar;
|
||||
else {
|
||||
return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
|
||||
}
|
||||
}else{
|
||||
|
||||
let tagEndExp = '</' + key + this.tagEndChar;
|
||||
let piClosingChar = "";
|
||||
|
||||
if(key[0] === "?") {
|
||||
piClosingChar = "?";
|
||||
tagEndExp = "";
|
||||
}
|
||||
|
||||
// attrStr is an empty string in case the attribute came as undefined or null
|
||||
if ((attrStr || attrStr === '') && val.indexOf('<') === -1) {
|
||||
return ( this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' + val + tagEndExp );
|
||||
} else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) {
|
||||
return this.indentate(level) + `<!--${val}-->` + this.newLine;
|
||||
}else {
|
||||
return (
|
||||
this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
|
||||
val +
|
||||
this.indentate(level) + tagEndExp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.closeTag = function(key){
|
||||
let closeTag = "";
|
||||
if(this.options.unpairedTags.indexOf(key) !== -1){ //unpaired
|
||||
if(!this.options.suppressUnpairedNode) closeTag = "/"
|
||||
}else if(this.options.suppressEmptyNode){ //empty
|
||||
closeTag = "/";
|
||||
}else{
|
||||
closeTag = `></${key}`
|
||||
}
|
||||
return closeTag;
|
||||
}
|
||||
|
||||
function buildEmptyObjNode(val, key, attrStr, level) {
|
||||
if (val !== '') {
|
||||
return this.buildObjectNode(val, key, attrStr, level);
|
||||
} else {
|
||||
if(key[0] === "?") return this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar;
|
||||
else {
|
||||
return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
|
||||
// return this.buildTagStr(level,key, attrStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.buildTextValNode = function(val, key, attrStr, level) {
|
||||
if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
|
||||
return this.indentate(level) + `<![CDATA[${val}]]>` + this.newLine;
|
||||
}else if (this.options.commentPropName !== false && key === this.options.commentPropName) {
|
||||
return this.indentate(level) + `<!--${val}-->` + this.newLine;
|
||||
}else if(key[0] === "?") {//PI tag
|
||||
return this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar;
|
||||
}else{
|
||||
let textValue = this.options.tagValueProcessor(key, val);
|
||||
textValue = this.replaceEntitiesValue(textValue);
|
||||
|
||||
if( textValue === ''){
|
||||
return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
|
||||
}else{
|
||||
return this.indentate(level) + '<' + key + attrStr + '>' +
|
||||
textValue +
|
||||
'</' + key + this.tagEndChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Builder.prototype.replaceEntitiesValue = function(textValue){
|
||||
if(textValue && textValue.length > 0 && this.options.processEntities){
|
||||
for (let i=0; i<this.options.entities.length; i++) {
|
||||
const entity = this.options.entities[i];
|
||||
textValue = textValue.replace(entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
return textValue;
|
||||
}
|
||||
|
||||
function indentate(level) {
|
||||
return this.options.indentBy.repeat(level);
|
||||
}
|
||||
|
||||
function isAttribute(name /*, options*/) {
|
||||
if (name.startsWith(this.options.attributeNamePrefix) && name !== this.options.textNodeName) {
|
||||
return name.substr(this.attrPrefixLen);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Builder;
|
135
em2rp/node_modules/fast-xml-parser/src/xmlbuilder/orderedJs2Xml.js
generated
vendored
Normal file
135
em2rp/node_modules/fast-xml-parser/src/xmlbuilder/orderedJs2Xml.js
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
const EOL = "\n";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {array} jArray
|
||||
* @param {any} options
|
||||
* @returns
|
||||
*/
|
||||
function toXml(jArray, options) {
|
||||
let indentation = "";
|
||||
if (options.format && options.indentBy.length > 0) {
|
||||
indentation = EOL;
|
||||
}
|
||||
return arrToStr(jArray, options, "", indentation);
|
||||
}
|
||||
|
||||
function arrToStr(arr, options, jPath, indentation) {
|
||||
let xmlStr = "";
|
||||
let isPreviousElementTag = false;
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const tagObj = arr[i];
|
||||
const tagName = propName(tagObj);
|
||||
if(tagName === undefined) continue;
|
||||
|
||||
let newJPath = "";
|
||||
if (jPath.length === 0) newJPath = tagName
|
||||
else newJPath = `${jPath}.${tagName}`;
|
||||
|
||||
if (tagName === options.textNodeName) {
|
||||
let tagText = tagObj[tagName];
|
||||
if (!isStopNode(newJPath, options)) {
|
||||
tagText = options.tagValueProcessor(tagName, tagText);
|
||||
tagText = replaceEntitiesValue(tagText, options);
|
||||
}
|
||||
if (isPreviousElementTag) {
|
||||
xmlStr += indentation;
|
||||
}
|
||||
xmlStr += tagText;
|
||||
isPreviousElementTag = false;
|
||||
continue;
|
||||
} else if (tagName === options.cdataPropName) {
|
||||
if (isPreviousElementTag) {
|
||||
xmlStr += indentation;
|
||||
}
|
||||
xmlStr += `<![CDATA[${tagObj[tagName][0][options.textNodeName]}]]>`;
|
||||
isPreviousElementTag = false;
|
||||
continue;
|
||||
} else if (tagName === options.commentPropName) {
|
||||
xmlStr += indentation + `<!--${tagObj[tagName][0][options.textNodeName]}-->`;
|
||||
isPreviousElementTag = true;
|
||||
continue;
|
||||
} else if (tagName[0] === "?") {
|
||||
const attStr = attr_to_str(tagObj[":@"], options);
|
||||
const tempInd = tagName === "?xml" ? "" : indentation;
|
||||
let piTextNodeName = tagObj[tagName][0][options.textNodeName];
|
||||
piTextNodeName = piTextNodeName.length !== 0 ? " " + piTextNodeName : ""; //remove extra spacing
|
||||
xmlStr += tempInd + `<${tagName}${piTextNodeName}${attStr}?>`;
|
||||
isPreviousElementTag = true;
|
||||
continue;
|
||||
}
|
||||
let newIdentation = indentation;
|
||||
if (newIdentation !== "") {
|
||||
newIdentation += options.indentBy;
|
||||
}
|
||||
const attStr = attr_to_str(tagObj[":@"], options);
|
||||
const tagStart = indentation + `<${tagName}${attStr}`;
|
||||
const tagValue = arrToStr(tagObj[tagName], options, newJPath, newIdentation);
|
||||
if (options.unpairedTags.indexOf(tagName) !== -1) {
|
||||
if (options.suppressUnpairedNode) xmlStr += tagStart + ">";
|
||||
else xmlStr += tagStart + "/>";
|
||||
} else if ((!tagValue || tagValue.length === 0) && options.suppressEmptyNode) {
|
||||
xmlStr += tagStart + "/>";
|
||||
} else if (tagValue && tagValue.endsWith(">")) {
|
||||
xmlStr += tagStart + `>${tagValue}${indentation}</${tagName}>`;
|
||||
} else {
|
||||
xmlStr += tagStart + ">";
|
||||
if (tagValue && indentation !== "" && (tagValue.includes("/>") || tagValue.includes("</"))) {
|
||||
xmlStr += indentation + options.indentBy + tagValue + indentation;
|
||||
} else {
|
||||
xmlStr += tagValue;
|
||||
}
|
||||
xmlStr += `</${tagName}>`;
|
||||
}
|
||||
isPreviousElementTag = true;
|
||||
}
|
||||
|
||||
return xmlStr;
|
||||
}
|
||||
|
||||
function propName(obj) {
|
||||
const keys = Object.keys(obj);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if(!obj.hasOwnProperty(key)) continue;
|
||||
if (key !== ":@") return key;
|
||||
}
|
||||
}
|
||||
|
||||
function attr_to_str(attrMap, options) {
|
||||
let attrStr = "";
|
||||
if (attrMap && !options.ignoreAttributes) {
|
||||
for (let attr in attrMap) {
|
||||
if(!attrMap.hasOwnProperty(attr)) continue;
|
||||
let attrVal = options.attributeValueProcessor(attr, attrMap[attr]);
|
||||
attrVal = replaceEntitiesValue(attrVal, options);
|
||||
if (attrVal === true && options.suppressBooleanAttributes) {
|
||||
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`;
|
||||
} else {
|
||||
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return attrStr;
|
||||
}
|
||||
|
||||
function isStopNode(jPath, options) {
|
||||
jPath = jPath.substr(0, jPath.length - options.textNodeName.length - 1);
|
||||
let tagName = jPath.substr(jPath.lastIndexOf(".") + 1);
|
||||
for (let index in options.stopNodes) {
|
||||
if (options.stopNodes[index] === jPath || options.stopNodes[index] === "*." + tagName) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function replaceEntitiesValue(textValue, options) {
|
||||
if (textValue && textValue.length > 0 && options.processEntities) {
|
||||
for (let i = 0; i < options.entities.length; i++) {
|
||||
const entity = options.entities[i];
|
||||
textValue = textValue.replace(entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
return textValue;
|
||||
}
|
||||
module.exports = toXml;
|
0
em2rp/node_modules/fast-xml-parser/src/xmlbuilder/prettifyJs2Xml.js
generated
vendored
Normal file
0
em2rp/node_modules/fast-xml-parser/src/xmlbuilder/prettifyJs2Xml.js
generated
vendored
Normal file
153
em2rp/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
generated
vendored
Normal file
153
em2rp/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
const util = require('../util');
|
||||
|
||||
//TODO: handle comments
|
||||
function readDocType(xmlData, i){
|
||||
|
||||
const entities = {};
|
||||
if( xmlData[i + 3] === 'O' &&
|
||||
xmlData[i + 4] === 'C' &&
|
||||
xmlData[i + 5] === 'T' &&
|
||||
xmlData[i + 6] === 'Y' &&
|
||||
xmlData[i + 7] === 'P' &&
|
||||
xmlData[i + 8] === 'E')
|
||||
{
|
||||
i = i+9;
|
||||
let angleBracketsCount = 1;
|
||||
let hasBody = false, comment = false;
|
||||
let exp = "";
|
||||
for(;i<xmlData.length;i++){
|
||||
if (xmlData[i] === '<' && !comment) { //Determine the tag type
|
||||
if( hasBody && isEntity(xmlData, i)){
|
||||
i += 7;
|
||||
let entityName, val;
|
||||
[entityName, val,i] = readEntityExp(xmlData,i+1);
|
||||
if(val.indexOf("&") === -1) //Parameter entities are not supported
|
||||
entities[ validateEntityName(entityName) ] = {
|
||||
regx : RegExp( `&${entityName};`,"g"),
|
||||
val: val
|
||||
};
|
||||
}
|
||||
else if( hasBody && isElement(xmlData, i)) i += 8;//Not supported
|
||||
else if( hasBody && isAttlist(xmlData, i)) i += 8;//Not supported
|
||||
else if( hasBody && isNotation(xmlData, i)) i += 9;//Not supported
|
||||
else if( isComment) comment = true;
|
||||
else throw new Error("Invalid DOCTYPE");
|
||||
|
||||
angleBracketsCount++;
|
||||
exp = "";
|
||||
} else if (xmlData[i] === '>') { //Read tag content
|
||||
if(comment){
|
||||
if( xmlData[i - 1] === "-" && xmlData[i - 2] === "-"){
|
||||
comment = false;
|
||||
angleBracketsCount--;
|
||||
}
|
||||
}else{
|
||||
angleBracketsCount--;
|
||||
}
|
||||
if (angleBracketsCount === 0) {
|
||||
break;
|
||||
}
|
||||
}else if( xmlData[i] === '['){
|
||||
hasBody = true;
|
||||
}else{
|
||||
exp += xmlData[i];
|
||||
}
|
||||
}
|
||||
if(angleBracketsCount !== 0){
|
||||
throw new Error(`Unclosed DOCTYPE`);
|
||||
}
|
||||
}else{
|
||||
throw new Error(`Invalid Tag instead of DOCTYPE`);
|
||||
}
|
||||
return {entities, i};
|
||||
}
|
||||
|
||||
function readEntityExp(xmlData,i){
|
||||
//External entities are not supported
|
||||
// <!ENTITY ext SYSTEM "http://normal-website.com" >
|
||||
|
||||
//Parameter entities are not supported
|
||||
// <!ENTITY entityname "&anotherElement;">
|
||||
|
||||
//Internal entities are supported
|
||||
// <!ENTITY entityname "replacement text">
|
||||
|
||||
//read EntityName
|
||||
let entityName = "";
|
||||
for (; i < xmlData.length && (xmlData[i] !== "'" && xmlData[i] !== '"' ); i++) {
|
||||
// if(xmlData[i] === " ") continue;
|
||||
// else
|
||||
entityName += xmlData[i];
|
||||
}
|
||||
entityName = entityName.trim();
|
||||
if(entityName.indexOf(" ") !== -1) throw new Error("External entites are not supported");
|
||||
|
||||
//read Entity Value
|
||||
const startChar = xmlData[i++];
|
||||
let val = ""
|
||||
for (; i < xmlData.length && xmlData[i] !== startChar ; i++) {
|
||||
val += xmlData[i];
|
||||
}
|
||||
return [entityName, val, i];
|
||||
}
|
||||
|
||||
function isComment(xmlData, i){
|
||||
if(xmlData[i+1] === '!' &&
|
||||
xmlData[i+2] === '-' &&
|
||||
xmlData[i+3] === '-') return true
|
||||
return false
|
||||
}
|
||||
function isEntity(xmlData, i){
|
||||
if(xmlData[i+1] === '!' &&
|
||||
xmlData[i+2] === 'E' &&
|
||||
xmlData[i+3] === 'N' &&
|
||||
xmlData[i+4] === 'T' &&
|
||||
xmlData[i+5] === 'I' &&
|
||||
xmlData[i+6] === 'T' &&
|
||||
xmlData[i+7] === 'Y') return true
|
||||
return false
|
||||
}
|
||||
function isElement(xmlData, i){
|
||||
if(xmlData[i+1] === '!' &&
|
||||
xmlData[i+2] === 'E' &&
|
||||
xmlData[i+3] === 'L' &&
|
||||
xmlData[i+4] === 'E' &&
|
||||
xmlData[i+5] === 'M' &&
|
||||
xmlData[i+6] === 'E' &&
|
||||
xmlData[i+7] === 'N' &&
|
||||
xmlData[i+8] === 'T') return true
|
||||
return false
|
||||
}
|
||||
|
||||
function isAttlist(xmlData, i){
|
||||
if(xmlData[i+1] === '!' &&
|
||||
xmlData[i+2] === 'A' &&
|
||||
xmlData[i+3] === 'T' &&
|
||||
xmlData[i+4] === 'T' &&
|
||||
xmlData[i+5] === 'L' &&
|
||||
xmlData[i+6] === 'I' &&
|
||||
xmlData[i+7] === 'S' &&
|
||||
xmlData[i+8] === 'T') return true
|
||||
return false
|
||||
}
|
||||
function isNotation(xmlData, i){
|
||||
if(xmlData[i+1] === '!' &&
|
||||
xmlData[i+2] === 'N' &&
|
||||
xmlData[i+3] === 'O' &&
|
||||
xmlData[i+4] === 'T' &&
|
||||
xmlData[i+5] === 'A' &&
|
||||
xmlData[i+6] === 'T' &&
|
||||
xmlData[i+7] === 'I' &&
|
||||
xmlData[i+8] === 'O' &&
|
||||
xmlData[i+9] === 'N') return true
|
||||
return false
|
||||
}
|
||||
|
||||
function validateEntityName(name){
|
||||
if (util.isName(name))
|
||||
return name;
|
||||
else
|
||||
throw new Error(`Invalid entity name ${name}`);
|
||||
}
|
||||
|
||||
module.exports = readDocType;
|
48
em2rp/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js
generated
vendored
Normal file
48
em2rp/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
const defaultOptions = {
|
||||
preserveOrder: false,
|
||||
attributeNamePrefix: '@_',
|
||||
attributesGroupName: false,
|
||||
textNodeName: '#text',
|
||||
ignoreAttributes: true,
|
||||
removeNSPrefix: false, // remove NS from tag name or attribute name if true
|
||||
allowBooleanAttributes: false, //a tag can have attributes without any value
|
||||
//ignoreRootElement : false,
|
||||
parseTagValue: true,
|
||||
parseAttributeValue: false,
|
||||
trimValues: true, //Trim string values of tag and attributes
|
||||
cdataPropName: false,
|
||||
numberParseOptions: {
|
||||
hex: true,
|
||||
leadingZeros: true,
|
||||
eNotation: true
|
||||
},
|
||||
tagValueProcessor: function(tagName, val) {
|
||||
return val;
|
||||
},
|
||||
attributeValueProcessor: function(attrName, val) {
|
||||
return val;
|
||||
},
|
||||
stopNodes: [], //nested tags will not be parsed even for errors
|
||||
alwaysCreateTextNode: false,
|
||||
isArray: () => false,
|
||||
commentPropName: false,
|
||||
unpairedTags: [],
|
||||
processEntities: true,
|
||||
htmlEntities: false,
|
||||
ignoreDeclaration: false,
|
||||
ignorePiTags: false,
|
||||
transformTagName: false,
|
||||
transformAttributeName: false,
|
||||
updateTag: function(tagName, jPath, attrs){
|
||||
return tagName
|
||||
},
|
||||
// skipEmptyListItem: false
|
||||
};
|
||||
|
||||
const buildOptions = function(options) {
|
||||
return Object.assign({}, defaultOptions, options);
|
||||
};
|
||||
|
||||
exports.buildOptions = buildOptions;
|
||||
exports.defaultOptions = defaultOptions;
|
606
em2rp/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
generated
vendored
Normal file
606
em2rp/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
generated
vendored
Normal file
@ -0,0 +1,606 @@
|
||||
'use strict';
|
||||
///@ts-check
|
||||
|
||||
const util = require('../util');
|
||||
const xmlNode = require('./xmlNode');
|
||||
const readDocType = require("./DocTypeReader");
|
||||
const toNumber = require("strnum");
|
||||
const getIgnoreAttributesFn = require('../ignoreAttributes')
|
||||
|
||||
// const regx =
|
||||
// '<((!\\[CDATA\\[([\\s\\S]*?)(]]>))|((NAME:)?(NAME))([^>]*)>|((\\/)(NAME)\\s*>))([^<]*)'
|
||||
// .replace(/NAME/g, util.nameRegexp);
|
||||
|
||||
//const tagsRegx = new RegExp("<(\\/?[\\w:\\-\._]+)([^>]*)>(\\s*"+cdataRegx+")*([^<]+)?","g");
|
||||
//const tagsRegx = new RegExp("<(\\/?)((\\w*:)?([\\w:\\-\._]+))([^>]*)>([^<]*)("+cdataRegx+"([^<]*))*([^<]+)?","g");
|
||||
|
||||
class OrderedObjParser{
|
||||
constructor(options){
|
||||
this.options = options;
|
||||
this.currentNode = null;
|
||||
this.tagsNodeStack = [];
|
||||
this.docTypeEntities = {};
|
||||
this.lastEntities = {
|
||||
"apos" : { regex: /&(apos|#39|#x27);/g, val : "'"},
|
||||
"gt" : { regex: /&(gt|#62|#x3E);/g, val : ">"},
|
||||
"lt" : { regex: /&(lt|#60|#x3C);/g, val : "<"},
|
||||
"quot" : { regex: /&(quot|#34|#x22);/g, val : "\""},
|
||||
};
|
||||
this.ampEntity = { regex: /&(amp|#38|#x26);/g, val : "&"};
|
||||
this.htmlEntities = {
|
||||
"space": { regex: /&(nbsp|#160);/g, val: " " },
|
||||
// "lt" : { regex: /&(lt|#60);/g, val: "<" },
|
||||
// "gt" : { regex: /&(gt|#62);/g, val: ">" },
|
||||
// "amp" : { regex: /&(amp|#38);/g, val: "&" },
|
||||
// "quot" : { regex: /&(quot|#34);/g, val: "\"" },
|
||||
// "apos" : { regex: /&(apos|#39);/g, val: "'" },
|
||||
"cent" : { regex: /&(cent|#162);/g, val: "¢" },
|
||||
"pound" : { regex: /&(pound|#163);/g, val: "£" },
|
||||
"yen" : { regex: /&(yen|#165);/g, val: "¥" },
|
||||
"euro" : { regex: /&(euro|#8364);/g, val: "€" },
|
||||
"copyright" : { regex: /&(copy|#169);/g, val: "©" },
|
||||
"reg" : { regex: /&(reg|#174);/g, val: "®" },
|
||||
"inr" : { regex: /&(inr|#8377);/g, val: "₹" },
|
||||
"num_dec": { regex: /&#([0-9]{1,7});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 10)) },
|
||||
"num_hex": { regex: /&#x([0-9a-fA-F]{1,6});/g, val : (_, str) => String.fromCharCode(Number.parseInt(str, 16)) },
|
||||
};
|
||||
this.addExternalEntities = addExternalEntities;
|
||||
this.parseXml = parseXml;
|
||||
this.parseTextData = parseTextData;
|
||||
this.resolveNameSpace = resolveNameSpace;
|
||||
this.buildAttributesMap = buildAttributesMap;
|
||||
this.isItStopNode = isItStopNode;
|
||||
this.replaceEntitiesValue = replaceEntitiesValue;
|
||||
this.readStopNodeData = readStopNodeData;
|
||||
this.saveTextToParentTag = saveTextToParentTag;
|
||||
this.addChild = addChild;
|
||||
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function addExternalEntities(externalEntities){
|
||||
const entKeys = Object.keys(externalEntities);
|
||||
for (let i = 0; i < entKeys.length; i++) {
|
||||
const ent = entKeys[i];
|
||||
this.lastEntities[ent] = {
|
||||
regex: new RegExp("&"+ent+";","g"),
|
||||
val : externalEntities[ent]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} val
|
||||
* @param {string} tagName
|
||||
* @param {string} jPath
|
||||
* @param {boolean} dontTrim
|
||||
* @param {boolean} hasAttributes
|
||||
* @param {boolean} isLeafNode
|
||||
* @param {boolean} escapeEntities
|
||||
*/
|
||||
function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) {
|
||||
if (val !== undefined) {
|
||||
if (this.options.trimValues && !dontTrim) {
|
||||
val = val.trim();
|
||||
}
|
||||
if(val.length > 0){
|
||||
if(!escapeEntities) val = this.replaceEntitiesValue(val);
|
||||
|
||||
const newval = this.options.tagValueProcessor(tagName, val, jPath, hasAttributes, isLeafNode);
|
||||
if(newval === null || newval === undefined){
|
||||
//don't parse
|
||||
return val;
|
||||
}else if(typeof newval !== typeof val || newval !== val){
|
||||
//overwrite
|
||||
return newval;
|
||||
}else if(this.options.trimValues){
|
||||
return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
|
||||
}else{
|
||||
const trimmedVal = val.trim();
|
||||
if(trimmedVal === val){
|
||||
return parseValue(val, this.options.parseTagValue, this.options.numberParseOptions);
|
||||
}else{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveNameSpace(tagname) {
|
||||
if (this.options.removeNSPrefix) {
|
||||
const tags = tagname.split(':');
|
||||
const prefix = tagname.charAt(0) === '/' ? '/' : '';
|
||||
if (tags[0] === 'xmlns') {
|
||||
return '';
|
||||
}
|
||||
if (tags.length === 2) {
|
||||
tagname = prefix + tags[1];
|
||||
}
|
||||
}
|
||||
return tagname;
|
||||
}
|
||||
|
||||
//TODO: change regex to capture NS
|
||||
//const attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])((.|\n)*?)\\2","gm");
|
||||
const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm');
|
||||
|
||||
function buildAttributesMap(attrStr, jPath, tagName) {
|
||||
if (this.options.ignoreAttributes !== true && typeof attrStr === 'string') {
|
||||
// attrStr = attrStr.replace(/\r?\n/g, ' ');
|
||||
//attrStr = attrStr || attrStr.trim();
|
||||
|
||||
const matches = util.getAllMatches(attrStr, attrsRegx);
|
||||
const len = matches.length; //don't make it inline
|
||||
const attrs = {};
|
||||
for (let i = 0; i < len; i++) {
|
||||
const attrName = this.resolveNameSpace(matches[i][1]);
|
||||
if (this.ignoreAttributesFn(attrName, jPath)) {
|
||||
continue
|
||||
}
|
||||
let oldVal = matches[i][4];
|
||||
let aName = this.options.attributeNamePrefix + attrName;
|
||||
if (attrName.length) {
|
||||
if (this.options.transformAttributeName) {
|
||||
aName = this.options.transformAttributeName(aName);
|
||||
}
|
||||
if(aName === "__proto__") aName = "#__proto__";
|
||||
if (oldVal !== undefined) {
|
||||
if (this.options.trimValues) {
|
||||
oldVal = oldVal.trim();
|
||||
}
|
||||
oldVal = this.replaceEntitiesValue(oldVal);
|
||||
const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPath);
|
||||
if(newVal === null || newVal === undefined){
|
||||
//don't parse
|
||||
attrs[aName] = oldVal;
|
||||
}else if(typeof newVal !== typeof oldVal || newVal !== oldVal){
|
||||
//overwrite
|
||||
attrs[aName] = newVal;
|
||||
}else{
|
||||
//parse
|
||||
attrs[aName] = parseValue(
|
||||
oldVal,
|
||||
this.options.parseAttributeValue,
|
||||
this.options.numberParseOptions
|
||||
);
|
||||
}
|
||||
} else if (this.options.allowBooleanAttributes) {
|
||||
attrs[aName] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Object.keys(attrs).length) {
|
||||
return;
|
||||
}
|
||||
if (this.options.attributesGroupName) {
|
||||
const attrCollection = {};
|
||||
attrCollection[this.options.attributesGroupName] = attrs;
|
||||
return attrCollection;
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
}
|
||||
|
||||
const parseXml = function(xmlData) {
|
||||
xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line
|
||||
const xmlObj = new xmlNode('!xml');
|
||||
let currentNode = xmlObj;
|
||||
let textData = "";
|
||||
let jPath = "";
|
||||
for(let i=0; i< xmlData.length; i++){//for each char in XML data
|
||||
const ch = xmlData[i];
|
||||
if(ch === '<'){
|
||||
// const nextIndex = i+1;
|
||||
// const _2ndChar = xmlData[nextIndex];
|
||||
if( xmlData[i+1] === '/') {//Closing Tag
|
||||
const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed.")
|
||||
let tagName = xmlData.substring(i+2,closeIndex).trim();
|
||||
|
||||
if(this.options.removeNSPrefix){
|
||||
const colonIndex = tagName.indexOf(":");
|
||||
if(colonIndex !== -1){
|
||||
tagName = tagName.substr(colonIndex+1);
|
||||
}
|
||||
}
|
||||
|
||||
if(this.options.transformTagName) {
|
||||
tagName = this.options.transformTagName(tagName);
|
||||
}
|
||||
|
||||
if(currentNode){
|
||||
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
||||
}
|
||||
|
||||
//check if last tag of nested tag was unpaired tag
|
||||
const lastTagName = jPath.substring(jPath.lastIndexOf(".")+1);
|
||||
if(tagName && this.options.unpairedTags.indexOf(tagName) !== -1 ){
|
||||
throw new Error(`Unpaired tag can not be used as closing tag: </${tagName}>`);
|
||||
}
|
||||
let propIndex = 0
|
||||
if(lastTagName && this.options.unpairedTags.indexOf(lastTagName) !== -1 ){
|
||||
propIndex = jPath.lastIndexOf('.', jPath.lastIndexOf('.')-1)
|
||||
this.tagsNodeStack.pop();
|
||||
}else{
|
||||
propIndex = jPath.lastIndexOf(".");
|
||||
}
|
||||
jPath = jPath.substring(0, propIndex);
|
||||
|
||||
currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope
|
||||
textData = "";
|
||||
i = closeIndex;
|
||||
} else if( xmlData[i+1] === '?') {
|
||||
|
||||
let tagData = readTagExp(xmlData,i, false, "?>");
|
||||
if(!tagData) throw new Error("Pi Tag is not closed.");
|
||||
|
||||
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
||||
if( (this.options.ignoreDeclaration && tagData.tagName === "?xml") || this.options.ignorePiTags){
|
||||
|
||||
}else{
|
||||
|
||||
const childNode = new xmlNode(tagData.tagName);
|
||||
childNode.add(this.options.textNodeName, "");
|
||||
|
||||
if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
|
||||
childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath, tagData.tagName);
|
||||
}
|
||||
this.addChild(currentNode, childNode, jPath)
|
||||
|
||||
}
|
||||
|
||||
|
||||
i = tagData.closeIndex + 1;
|
||||
} else if(xmlData.substr(i + 1, 3) === '!--') {
|
||||
const endIndex = findClosingIndex(xmlData, "-->", i+4, "Comment is not closed.")
|
||||
if(this.options.commentPropName){
|
||||
const comment = xmlData.substring(i + 4, endIndex - 2);
|
||||
|
||||
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
||||
|
||||
currentNode.add(this.options.commentPropName, [ { [this.options.textNodeName] : comment } ]);
|
||||
}
|
||||
i = endIndex;
|
||||
} else if( xmlData.substr(i + 1, 2) === '!D') {
|
||||
const result = readDocType(xmlData, i);
|
||||
this.docTypeEntities = result.entities;
|
||||
i = result.i;
|
||||
}else if(xmlData.substr(i + 1, 2) === '![') {
|
||||
const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2;
|
||||
const tagExp = xmlData.substring(i + 9,closeIndex);
|
||||
|
||||
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
||||
|
||||
let val = this.parseTextData(tagExp, currentNode.tagname, jPath, true, false, true, true);
|
||||
if(val == undefined) val = "";
|
||||
|
||||
//cdata should be set even if it is 0 length string
|
||||
if(this.options.cdataPropName){
|
||||
currentNode.add(this.options.cdataPropName, [ { [this.options.textNodeName] : tagExp } ]);
|
||||
}else{
|
||||
currentNode.add(this.options.textNodeName, val);
|
||||
}
|
||||
|
||||
i = closeIndex + 2;
|
||||
}else {//Opening tag
|
||||
let result = readTagExp(xmlData,i, this.options.removeNSPrefix);
|
||||
let tagName= result.tagName;
|
||||
const rawTagName = result.rawTagName;
|
||||
let tagExp = result.tagExp;
|
||||
let attrExpPresent = result.attrExpPresent;
|
||||
let closeIndex = result.closeIndex;
|
||||
|
||||
if (this.options.transformTagName) {
|
||||
tagName = this.options.transformTagName(tagName);
|
||||
}
|
||||
|
||||
//save text as child node
|
||||
if (currentNode && textData) {
|
||||
if(currentNode.tagname !== '!xml'){
|
||||
//when nested tag is found
|
||||
textData = this.saveTextToParentTag(textData, currentNode, jPath, false);
|
||||
}
|
||||
}
|
||||
|
||||
//check if last tag was unpaired tag
|
||||
const lastTag = currentNode;
|
||||
if(lastTag && this.options.unpairedTags.indexOf(lastTag.tagname) !== -1 ){
|
||||
currentNode = this.tagsNodeStack.pop();
|
||||
jPath = jPath.substring(0, jPath.lastIndexOf("."));
|
||||
}
|
||||
if(tagName !== xmlObj.tagname){
|
||||
jPath += jPath ? "." + tagName : tagName;
|
||||
}
|
||||
if (this.isItStopNode(this.options.stopNodes, jPath, tagName)) {
|
||||
let tagContent = "";
|
||||
//self-closing tag
|
||||
if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
|
||||
if(tagName[tagName.length - 1] === "/"){ //remove trailing '/'
|
||||
tagName = tagName.substr(0, tagName.length - 1);
|
||||
jPath = jPath.substr(0, jPath.length - 1);
|
||||
tagExp = tagName;
|
||||
}else{
|
||||
tagExp = tagExp.substr(0, tagExp.length - 1);
|
||||
}
|
||||
i = result.closeIndex;
|
||||
}
|
||||
//unpaired tag
|
||||
else if(this.options.unpairedTags.indexOf(tagName) !== -1){
|
||||
|
||||
i = result.closeIndex;
|
||||
}
|
||||
//normal tag
|
||||
else{
|
||||
//read until closing tag is found
|
||||
const result = this.readStopNodeData(xmlData, rawTagName, closeIndex + 1);
|
||||
if(!result) throw new Error(`Unexpected end of ${rawTagName}`);
|
||||
i = result.i;
|
||||
tagContent = result.tagContent;
|
||||
}
|
||||
|
||||
const childNode = new xmlNode(tagName);
|
||||
if(tagName !== tagExp && attrExpPresent){
|
||||
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
|
||||
}
|
||||
if(tagContent) {
|
||||
tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true);
|
||||
}
|
||||
|
||||
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
||||
childNode.add(this.options.textNodeName, tagContent);
|
||||
|
||||
this.addChild(currentNode, childNode, jPath)
|
||||
}else{
|
||||
//selfClosing tag
|
||||
if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
|
||||
if(tagName[tagName.length - 1] === "/"){ //remove trailing '/'
|
||||
tagName = tagName.substr(0, tagName.length - 1);
|
||||
jPath = jPath.substr(0, jPath.length - 1);
|
||||
tagExp = tagName;
|
||||
}else{
|
||||
tagExp = tagExp.substr(0, tagExp.length - 1);
|
||||
}
|
||||
|
||||
if(this.options.transformTagName) {
|
||||
tagName = this.options.transformTagName(tagName);
|
||||
}
|
||||
|
||||
const childNode = new xmlNode(tagName);
|
||||
if(tagName !== tagExp && attrExpPresent){
|
||||
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
|
||||
}
|
||||
this.addChild(currentNode, childNode, jPath)
|
||||
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
||||
}
|
||||
//opening tag
|
||||
else{
|
||||
const childNode = new xmlNode( tagName);
|
||||
this.tagsNodeStack.push(currentNode);
|
||||
|
||||
if(tagName !== tagExp && attrExpPresent){
|
||||
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
|
||||
}
|
||||
this.addChild(currentNode, childNode, jPath)
|
||||
currentNode = childNode;
|
||||
}
|
||||
textData = "";
|
||||
i = closeIndex;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
textData += xmlData[i];
|
||||
}
|
||||
}
|
||||
return xmlObj.child;
|
||||
}
|
||||
|
||||
function addChild(currentNode, childNode, jPath){
|
||||
const result = this.options.updateTag(childNode.tagname, jPath, childNode[":@"])
|
||||
if(result === false){
|
||||
}else if(typeof result === "string"){
|
||||
childNode.tagname = result
|
||||
currentNode.addChild(childNode);
|
||||
}else{
|
||||
currentNode.addChild(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
const replaceEntitiesValue = function(val){
|
||||
|
||||
if(this.options.processEntities){
|
||||
for(let entityName in this.docTypeEntities){
|
||||
const entity = this.docTypeEntities[entityName];
|
||||
val = val.replace( entity.regx, entity.val);
|
||||
}
|
||||
for(let entityName in this.lastEntities){
|
||||
const entity = this.lastEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
if(this.options.htmlEntities){
|
||||
for(let entityName in this.htmlEntities){
|
||||
const entity = this.htmlEntities[entityName];
|
||||
val = val.replace( entity.regex, entity.val);
|
||||
}
|
||||
}
|
||||
val = val.replace( this.ampEntity.regex, this.ampEntity.val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) {
|
||||
if (textData) { //store previously collected data as textNode
|
||||
if(isLeafNode === undefined) isLeafNode = currentNode.child.length === 0
|
||||
|
||||
textData = this.parseTextData(textData,
|
||||
currentNode.tagname,
|
||||
jPath,
|
||||
false,
|
||||
currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false,
|
||||
isLeafNode);
|
||||
|
||||
if (textData !== undefined && textData !== "")
|
||||
currentNode.add(this.options.textNodeName, textData);
|
||||
textData = "";
|
||||
}
|
||||
return textData;
|
||||
}
|
||||
|
||||
//TODO: use jPath to simplify the logic
|
||||
/**
|
||||
*
|
||||
* @param {string[]} stopNodes
|
||||
* @param {string} jPath
|
||||
* @param {string} currentTagName
|
||||
*/
|
||||
function isItStopNode(stopNodes, jPath, currentTagName){
|
||||
const allNodesExp = "*." + currentTagName;
|
||||
for (const stopNodePath in stopNodes) {
|
||||
const stopNodeExp = stopNodes[stopNodePath];
|
||||
if( allNodesExp === stopNodeExp || jPath === stopNodeExp ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tag Expression and where it is ending handling single-double quotes situation
|
||||
* @param {string} xmlData
|
||||
* @param {number} i starting index
|
||||
* @returns
|
||||
*/
|
||||
function tagExpWithClosingIndex(xmlData, i, closingChar = ">"){
|
||||
let attrBoundary;
|
||||
let tagExp = "";
|
||||
for (let index = i; index < xmlData.length; index++) {
|
||||
let ch = xmlData[index];
|
||||
if (attrBoundary) {
|
||||
if (ch === attrBoundary) attrBoundary = "";//reset
|
||||
} else if (ch === '"' || ch === "'") {
|
||||
attrBoundary = ch;
|
||||
} else if (ch === closingChar[0]) {
|
||||
if(closingChar[1]){
|
||||
if(xmlData[index + 1] === closingChar[1]){
|
||||
return {
|
||||
data: tagExp,
|
||||
index: index
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return {
|
||||
data: tagExp,
|
||||
index: index
|
||||
}
|
||||
}
|
||||
} else if (ch === '\t') {
|
||||
ch = " "
|
||||
}
|
||||
tagExp += ch;
|
||||
}
|
||||
}
|
||||
|
||||
function findClosingIndex(xmlData, str, i, errMsg){
|
||||
const closingIndex = xmlData.indexOf(str, i);
|
||||
if(closingIndex === -1){
|
||||
throw new Error(errMsg)
|
||||
}else{
|
||||
return closingIndex + str.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
function readTagExp(xmlData,i, removeNSPrefix, closingChar = ">"){
|
||||
const result = tagExpWithClosingIndex(xmlData, i+1, closingChar);
|
||||
if(!result) return;
|
||||
let tagExp = result.data;
|
||||
const closeIndex = result.index;
|
||||
const separatorIndex = tagExp.search(/\s/);
|
||||
let tagName = tagExp;
|
||||
let attrExpPresent = true;
|
||||
if(separatorIndex !== -1){//separate tag name and attributes expression
|
||||
tagName = tagExp.substring(0, separatorIndex);
|
||||
tagExp = tagExp.substring(separatorIndex + 1).trimStart();
|
||||
}
|
||||
|
||||
const rawTagName = tagName;
|
||||
if(removeNSPrefix){
|
||||
const colonIndex = tagName.indexOf(":");
|
||||
if(colonIndex !== -1){
|
||||
tagName = tagName.substr(colonIndex+1);
|
||||
attrExpPresent = tagName !== result.data.substr(colonIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tagName: tagName,
|
||||
tagExp: tagExp,
|
||||
closeIndex: closeIndex,
|
||||
attrExpPresent: attrExpPresent,
|
||||
rawTagName: rawTagName,
|
||||
}
|
||||
}
|
||||
/**
|
||||
* find paired tag for a stop node
|
||||
* @param {string} xmlData
|
||||
* @param {string} tagName
|
||||
* @param {number} i
|
||||
*/
|
||||
function readStopNodeData(xmlData, tagName, i){
|
||||
const startIndex = i;
|
||||
// Starting at 1 since we already have an open tag
|
||||
let openTagCount = 1;
|
||||
|
||||
for (; i < xmlData.length; i++) {
|
||||
if( xmlData[i] === "<"){
|
||||
if (xmlData[i+1] === "/") {//close tag
|
||||
const closeIndex = findClosingIndex(xmlData, ">", i, `${tagName} is not closed`);
|
||||
let closeTagName = xmlData.substring(i+2,closeIndex).trim();
|
||||
if(closeTagName === tagName){
|
||||
openTagCount--;
|
||||
if (openTagCount === 0) {
|
||||
return {
|
||||
tagContent: xmlData.substring(startIndex, i),
|
||||
i : closeIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
i=closeIndex;
|
||||
} else if(xmlData[i+1] === '?') {
|
||||
const closeIndex = findClosingIndex(xmlData, "?>", i+1, "StopNode is not closed.")
|
||||
i=closeIndex;
|
||||
} else if(xmlData.substr(i + 1, 3) === '!--') {
|
||||
const closeIndex = findClosingIndex(xmlData, "-->", i+3, "StopNode is not closed.")
|
||||
i=closeIndex;
|
||||
} else if(xmlData.substr(i + 1, 2) === '![') {
|
||||
const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
|
||||
i=closeIndex;
|
||||
} else {
|
||||
const tagData = readTagExp(xmlData, i, '>')
|
||||
|
||||
if (tagData) {
|
||||
const openTagName = tagData && tagData.tagName;
|
||||
if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length-1] !== "/") {
|
||||
openTagCount++;
|
||||
}
|
||||
i=tagData.closeIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}//end for loop
|
||||
}
|
||||
|
||||
function parseValue(val, shouldParse, options) {
|
||||
if (shouldParse && typeof val === 'string') {
|
||||
//console.log(options)
|
||||
const newval = val.trim();
|
||||
if(newval === 'true' ) return true;
|
||||
else if(newval === 'false' ) return false;
|
||||
else return toNumber(val, options);
|
||||
} else {
|
||||
if (util.isExist(val)) {
|
||||
return val;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = OrderedObjParser;
|
58
em2rp/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js
generated
vendored
Normal file
58
em2rp/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
const { buildOptions} = require("./OptionsBuilder");
|
||||
const OrderedObjParser = require("./OrderedObjParser");
|
||||
const { prettify} = require("./node2json");
|
||||
const validator = require('../validator');
|
||||
|
||||
class XMLParser{
|
||||
|
||||
constructor(options){
|
||||
this.externalEntities = {};
|
||||
this.options = buildOptions(options);
|
||||
|
||||
}
|
||||
/**
|
||||
* Parse XML dats to JS object
|
||||
* @param {string|Buffer} xmlData
|
||||
* @param {boolean|Object} validationOption
|
||||
*/
|
||||
parse(xmlData,validationOption){
|
||||
if(typeof xmlData === "string"){
|
||||
}else if( xmlData.toString){
|
||||
xmlData = xmlData.toString();
|
||||
}else{
|
||||
throw new Error("XML data is accepted in String or Bytes[] form.")
|
||||
}
|
||||
if( validationOption){
|
||||
if(validationOption === true) validationOption = {}; //validate with default options
|
||||
|
||||
const result = validator.validate(xmlData, validationOption);
|
||||
if (result !== true) {
|
||||
throw Error( `${result.err.msg}:${result.err.line}:${result.err.col}` )
|
||||
}
|
||||
}
|
||||
const orderedObjParser = new OrderedObjParser(this.options);
|
||||
orderedObjParser.addExternalEntities(this.externalEntities);
|
||||
const orderedResult = orderedObjParser.parseXml(xmlData);
|
||||
if(this.options.preserveOrder || orderedResult === undefined) return orderedResult;
|
||||
else return prettify(orderedResult, this.options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Entity which is not by default supported by this library
|
||||
* @param {string} key
|
||||
* @param {string} value
|
||||
*/
|
||||
addEntity(key, value){
|
||||
if(value.indexOf("&") !== -1){
|
||||
throw new Error("Entity value can't have '&'")
|
||||
}else if(key.indexOf("&") !== -1 || key.indexOf(";") !== -1){
|
||||
throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '
'")
|
||||
}else if(value === "&"){
|
||||
throw new Error("An entity with value '&' is not permitted");
|
||||
}else{
|
||||
this.externalEntities[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = XMLParser;
|
113
em2rp/node_modules/fast-xml-parser/src/xmlparser/node2json.js
generated
vendored
Normal file
113
em2rp/node_modules/fast-xml-parser/src/xmlparser/node2json.js
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {array} node
|
||||
* @param {any} options
|
||||
* @returns
|
||||
*/
|
||||
function prettify(node, options){
|
||||
return compress( node, options);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {array} arr
|
||||
* @param {object} options
|
||||
* @param {string} jPath
|
||||
* @returns object
|
||||
*/
|
||||
function compress(arr, options, jPath){
|
||||
let text;
|
||||
const compressedObj = {};
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const tagObj = arr[i];
|
||||
const property = propName(tagObj);
|
||||
let newJpath = "";
|
||||
if(jPath === undefined) newJpath = property;
|
||||
else newJpath = jPath + "." + property;
|
||||
|
||||
if(property === options.textNodeName){
|
||||
if(text === undefined) text = tagObj[property];
|
||||
else text += "" + tagObj[property];
|
||||
}else if(property === undefined){
|
||||
continue;
|
||||
}else if(tagObj[property]){
|
||||
|
||||
let val = compress(tagObj[property], options, newJpath);
|
||||
const isLeaf = isLeafTag(val, options);
|
||||
|
||||
if(tagObj[":@"]){
|
||||
assignAttributes( val, tagObj[":@"], newJpath, options);
|
||||
}else if(Object.keys(val).length === 1 && val[options.textNodeName] !== undefined && !options.alwaysCreateTextNode){
|
||||
val = val[options.textNodeName];
|
||||
}else if(Object.keys(val).length === 0){
|
||||
if(options.alwaysCreateTextNode) val[options.textNodeName] = "";
|
||||
else val = "";
|
||||
}
|
||||
|
||||
if(compressedObj[property] !== undefined && compressedObj.hasOwnProperty(property)) {
|
||||
if(!Array.isArray(compressedObj[property])) {
|
||||
compressedObj[property] = [ compressedObj[property] ];
|
||||
}
|
||||
compressedObj[property].push(val);
|
||||
}else{
|
||||
//TODO: if a node is not an array, then check if it should be an array
|
||||
//also determine if it is a leaf node
|
||||
if (options.isArray(property, newJpath, isLeaf )) {
|
||||
compressedObj[property] = [val];
|
||||
}else{
|
||||
compressedObj[property] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// if(text && text.length > 0) compressedObj[options.textNodeName] = text;
|
||||
if(typeof text === "string"){
|
||||
if(text.length > 0) compressedObj[options.textNodeName] = text;
|
||||
}else if(text !== undefined) compressedObj[options.textNodeName] = text;
|
||||
return compressedObj;
|
||||
}
|
||||
|
||||
function propName(obj){
|
||||
const keys = Object.keys(obj);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if(key !== ":@") return key;
|
||||
}
|
||||
}
|
||||
|
||||
function assignAttributes(obj, attrMap, jpath, options){
|
||||
if (attrMap) {
|
||||
const keys = Object.keys(attrMap);
|
||||
const len = keys.length; //don't make it inline
|
||||
for (let i = 0; i < len; i++) {
|
||||
const atrrName = keys[i];
|
||||
if (options.isArray(atrrName, jpath + "." + atrrName, true, true)) {
|
||||
obj[atrrName] = [ attrMap[atrrName] ];
|
||||
} else {
|
||||
obj[atrrName] = attrMap[atrrName];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isLeafTag(obj, options){
|
||||
const { textNodeName } = options;
|
||||
const propCount = Object.keys(obj).length;
|
||||
|
||||
if (propCount === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
propCount === 1 &&
|
||||
(obj[textNodeName] || typeof obj[textNodeName] === "boolean" || obj[textNodeName] === 0)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
exports.prettify = prettify;
|
25
em2rp/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js
generated
vendored
Normal file
25
em2rp/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
class XmlNode{
|
||||
constructor(tagname) {
|
||||
this.tagname = tagname;
|
||||
this.child = []; //nested tags, text, cdata, comments in order
|
||||
this[":@"] = {}; //attributes map
|
||||
}
|
||||
add(key,val){
|
||||
// this.child.push( {name : key, val: val, isCdata: isCdata });
|
||||
if(key === "__proto__") key = "#__proto__";
|
||||
this.child.push( {[key]: val });
|
||||
}
|
||||
addChild(node) {
|
||||
if(node.tagname === "__proto__") node.tagname = "#__proto__";
|
||||
if(node[":@"] && Object.keys(node[":@"]).length > 0){
|
||||
this.child.push( { [node.tagname]: node.child, [":@"]: node[":@"] });
|
||||
}else{
|
||||
this.child.push( { [node.tagname]: node.child });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
module.exports = XmlNode;
|
Reference in New Issue
Block a user