Galerie und tage
This commit is contained in:
21
node_modules/fast-xml-parser/LICENSE
generated
vendored
21
node_modules/fast-xml-parser/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Amit Kumar Gupta
|
||||
|
||||
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.
|
||||
367
node_modules/fast-xml-parser/README.md
generated
vendored
367
node_modules/fast-xml-parser/README.md
generated
vendored
@@ -1,367 +0,0 @@
|
||||
|
||||
|
||||
# [fast-xml-parser](https://www.npmjs.com/package/fast-xml-parser)
|
||||
[](#backers) [](#sponsors) [](https://snyk.io/test/github/naturalintelligence/fast-xml-parser)
|
||||
[![NPM quality][quality-image]][quality-url]
|
||||
[](https://travis-ci.org/NaturalIntelligence/fast-xml-parser)
|
||||
[](https://coveralls.io/github/NaturalIntelligence/fast-xml-parser?branch=master)
|
||||
[<img src="https://img.shields.io/badge/Try-me-blue.svg?colorA=FFA500&colorB=0000FF" alt="Try me"/>](https://naturalintelligence.github.io/fast-xml-parser/)
|
||||
[](https://npm.im/fast-xml-parser)
|
||||
|
||||
[quality-image]: http://npm.packagequality.com/shield/fast-xml-parser.svg?style=flat-square
|
||||
[quality-url]: http://packagequality.com/#?package=fast-xml-parser
|
||||
|
||||
|
||||
Validate XML, Parse XML to JS/JSON and vice versa, or parse XML to Nimn rapidly without C/C++ based libraries and no callback
|
||||
|
||||
To cover expenses, we're planning to launch [FXP Enterprise](https://github.com/NaturalIntelligence/fxp-ent) edition in parallel. Watch it for further updates, if you're interested.
|
||||
|
||||

|
||||
|
||||
<a href="https://opencollective.com/fast-xml-parser/donate" target="_blank">
|
||||
<img src="https://opencollective.com/fast-xml-parser/donate/button@2x.png?color=blue" width=200 />
|
||||
</a>
|
||||
<a href="https://paypal.me/naturalintelligence"> <img src="static/img/support_paypal.svg" alt="Stubmatic donate button" width="200"/></a>
|
||||
|
||||
Check [ThankYouBackers](https://github.com/NaturalIntelligence/ThankYouBackers) for our contributors
|
||||
|
||||
## Users
|
||||
List of some applications/projects using Fast XML Parser. (Raise an issue to submit yours)
|
||||
|
||||
<a href="https://github.com/NaturalIntelligence/imglab" title="imglab" ><img src="https://github.com/NaturalIntelligence/imglab/blob/master/img/imglab_logo.png?raw=true" width="80px" ></a>
|
||||
<a href="https://github.com/NaturalIntelligence/Stubmatic" title="stubmatic" ><img src="https://camo.githubusercontent.com/ff711425dc2286cd215637b7114eb43e571f001d/68747470733a2f2f6e61747572616c696e74656c6c6967656e63652e6769746875622e696f2f537475626d617469632f696d672f737475626d617469635f6c6f676f2e706e673f7261773d74727565" width="80px" ></a>
|
||||
<a href="https://github.com/muneem4node/muneem" title="Muneem" ><img src="https://github.com/muneem4node/muneem/raw/master/static/muneem.png?raw=true" width="80px" ></a>
|
||||
<a href="https://github.com/badges/shields" title="shields" ><img src="https://avatars2.githubusercontent.com/u/6254238" width="80px" ></a>
|
||||
<a href="https://github.com/renovatebot/renovate" title="renovate" ><img src="https://avatars1.githubusercontent.com/u/38656520" width="80px" ></a>
|
||||
<a href="https://vmware.com/" title="vmware" > <img src="https://avatars0.githubusercontent.com/u/473334" width="80px" ></a>
|
||||
<a href="https://opensource.microsoft.com/" title="microsoft" > <img src="https://avatars0.githubusercontent.com/u/6154722" width="80px" ></a>
|
||||
<a href="https://github.com/notable/notable" title="notable" > <img src="https://avatars3.githubusercontent.com/u/46467536" width="80px" ></a>
|
||||
<a href="http://ibm.github.io/" title="IBM" > <img src="https://avatars2.githubusercontent.com/u/1459110" width="80px" ></a>
|
||||
<a href="https://www.ft.com/" title="Financial Times" > <img src="https://avatars2.githubusercontent.com/u/3502508" width="80px" ></a>
|
||||
<a href="https://github.com/camunda" title="camunda BPM" > <img src="https://avatars3.githubusercontent.com/u/2443838" width="80px" ></a>
|
||||
<a href="https://github.com/AnyChart" title="AnyChart" > <img src="https://avatars0.githubusercontent.com/u/703373" width="80px" ></a>
|
||||
<a href="https://github.com/magda-io" title="magda-io" > <img src="https://avatars0.githubusercontent.com/u/40348684" width="80px" ></a>
|
||||
<a href="https://github.com/geistinteractive" title="Geist Interactive" > <img src="https://avatars0.githubusercontent.com/u/11617965" width="80px" ></a>
|
||||
<a href="https://www.tourstream.eu/" title="tourstream" > <img src="https://avatars1.githubusercontent.com/u/23242088" width="80px" ></a>
|
||||
<a href="https://www.atomist.com/" title="Atomist" > <img src="https://avatars3.githubusercontent.com/u/19392" width="80px" ></a>
|
||||
<a href="http://www.opuscapita.com/" title="OpusCapita" > <img src="https://avatars1.githubusercontent.com/u/23256480" width="80px" ></a>
|
||||
<a href="https://nevatrip.ru/" title="nevatrip" > <img src="https://avatars2.githubusercontent.com/u/35730984" width="80px" ></a>
|
||||
<a href="http://www.smartbear.com" title="SmartBear Software" > <img src="https://avatars2.githubusercontent.com/u/1644671" width="80px" ></a>
|
||||
<a href="http://eosnavigator.com/" title="nevatrip" > <img src="https://avatars1.githubusercontent.com/u/40260563" width="80px" ></a>
|
||||
<a href="http://nasa.github.io/" title="NASA" > <img src="https://avatars0.githubusercontent.com/u/848102" width="80px" ></a>
|
||||
<a href="http://qgis.org/" title="QGIS" > <img src="https://avatars2.githubusercontent.com/u/483444" width="80px" ></a>
|
||||
<a href="http://www.craft.ai/" title="craft ai" > <img src="https://avatars1.githubusercontent.com/u/12046764" width="80px" ></a>
|
||||
<a href="http://brownspace.org/" title="Brown Space Engineering" > <img src="https://avatars2.githubusercontent.com/u/5504507" width="80px" ></a>
|
||||
<a href="http://www.appcelerator.com/" title="Team Appcelerator" > <img src="https://avatars1.githubusercontent.com/u/82188" width="80px" ></a>
|
||||
<a href="https://xmllint.com/" title="XML Lint" > <img src="https://xmllint.com/assets/logo.png" width="80px" ></a>
|
||||
<a href="https://github.com/prettier" title="Prettier" > <img src="https://avatars0.githubusercontent.com/u/25822731" width="80px" ></a>
|
||||
<a href="https://github.com/dolanmiu/docx" title="docx" > <img src="https://i.imgur.com/37uBGhO.gif" width="80px" ></a>
|
||||
<a href="http://orange-opensource.github.io/" title="Open Source by Orange" > <img src="https://avatars3.githubusercontent.com/u/1506386" width="80px" ></a>
|
||||
<a href="http://www.ybrain.com/" title="YBRAIN Inc." > <img src="https://avatars2.githubusercontent.com/u/38232440" width="80px" ></a>
|
||||
<a href="http://99bitcoins.com/" title="99 bitcoins" > <img src="https://avatars0.githubusercontent.com/u/9527779" width="80px" ></a>
|
||||
<a href="https://wechaty.github.io/wechaty/" title="Wechaty" > <img src="https://avatars0.githubusercontent.com/u/21285357" width="80px" ></a>
|
||||
<a href="https://opendatakit.org" title="Open Data Kit" > <img src="https://avatars0.githubusercontent.com/u/6222985" width="80px" ></a>
|
||||
<a href="https://ridibooks.com" title="RIDI Books" > <img src="https://avatars1.githubusercontent.com/u/24955411" width="80px" ></a>
|
||||
<a href="http://signalk.org" title="Signal K" > <img src="https://avatars1.githubusercontent.com/u/7126740" width="80px" ></a>
|
||||
<a href="http://brain.js.org/" title="brain.js" > <img src="https://avatars2.githubusercontent.com/u/23732838" width="80px" ></a>
|
||||
<a href="https://skygear.io/" title="Skegear" > <img src="https://avatars1.githubusercontent.com/u/15025887" width="80px" ></a>
|
||||
<a href="https://npmjs.com/" title="npm" > <img src="https://avatars0.githubusercontent.com/u/6078720" width="80px" ></a>
|
||||
<a href=" https://www.mindpointgroup.com" title="mindpointgroup" > <img src="https://avatars1.githubusercontent.com/u/6413533" width="80px" ></a>
|
||||
<a href="http://www.acuantcorp.com/" title="Acuant Inc" > <img src="https://avatars3.githubusercontent.com/u/11580319?s=200&v=4" width="80px" ></a>
|
||||
<a href="https://www.wazuh.com/" title="wazuh" > <img src="https://avatars2.githubusercontent.com/u/13752566" width="80px" ></a>
|
||||
<a href="https://orbs.com/" title="ORBS The Hybrid Blockchain" > <img src="https://avatars1.githubusercontent.com/u/33665977" width="80px" ></a>
|
||||
<a href="https://texlab.netlify.com/" title="latex-lsp" > <img src="https://avatars1.githubusercontent.com/u/48360002" width="80px" ></a>
|
||||
<a href="https://frontside.io/" title="The Frontside " > <img src="https://avatars1.githubusercontent.com/u/223096" width="80px" ></a>
|
||||
<a href="https://creditsense.com.au/" title="Credit Sense Australia " > <img src="https://avatars0.githubusercontent.com/u/46947118" width="80px" ></a>
|
||||
<a href="https://www.hustunique.com/" title="UniqueStudio" > <img src="https://avatars1.githubusercontent.com/u/4847684" width="80px" ></a>
|
||||
<a href="http://www.openforis.org/" title="Open Foris" > <img src="https://avatars2.githubusercontent.com/u/1212750" width="80px" ></a>
|
||||
<a href="#" title="NHS Connect" > <img src="https://avatars3.githubusercontent.com/u/20316669" width="80px" ></a>
|
||||
<a href="https://tradle.io/" title="Tradle" > <img src="https://avatars2.githubusercontent.com/u/9482126" width="80px" ></a>
|
||||
<a href="http://www.anl.gov/" title="Argonne National Laboratory" > <img src="https://avatars0.githubusercontent.com/u/10468712" width="80px" ></a>
|
||||
<a href="https://simpleicons.org/" title="Simple Icons" > <img src="https://avatars2.githubusercontent.com/u/29872746" width="80px" ></a>
|
||||
<a href="https://stoplight.io/" title="Stoplight" > <img src="https://avatars1.githubusercontent.com/u/10767217" width="80px" ></a>
|
||||
<a href="http://www.fda.gov/" title="Food and Drug Administration " > <img src="https://avatars2.githubusercontent.com/u/6471964" width="80px" ></a>
|
||||
<a href="http://www.magento.com/" title="Magento" > <img src="https://avatars2.githubusercontent.com/u/168457" width="80px" ></a>
|
||||
|
||||
|
||||
The list of users is collected either from the list published by Github, cummunicated directly through mails/chat , or from other resources. If you feel that your name in the above list is incorrectly published or you're not the user of this library anymore then you can inform us to remove it. We'll do the necessary changes ASAP.
|
||||
|
||||
### Main Features
|
||||
|
||||
<img align="right" src="static/img/fxp_logo.png" width="180px" alt="FXP logo"/>
|
||||
|
||||
* Validate XML data syntactically
|
||||
* Transform XML to JSON or Nimn
|
||||
* Transform JSON back to XML
|
||||
* Works with node packages, in browser, and in CLI (press try me button above for demo)
|
||||
* Faster than any pure JS implementation.
|
||||
* It can handle big files (tested up to 100mb).
|
||||
* Various options are available to customize the transformation
|
||||
* You can parse CDATA as a separate property.
|
||||
* You can prefix attributes or group them to a separate property. Or they can be ignored from the result completely.
|
||||
* You can parse tag's or attribute's value to primitive type: string, integer, float, hexadecimal, or boolean. And can optionally decode for HTML char.
|
||||
* You can remove namespace from tag or attribute name while parsing
|
||||
* It supports boolean attributes, if configured.
|
||||
|
||||
## How to use
|
||||
|
||||
### Installation
|
||||
|
||||
To use it as an **NPM package**:
|
||||
|
||||
`npm install fast-xml-parser`
|
||||
|
||||
Or using [yarn](https://yarnpkg.com/):
|
||||
|
||||
`yarn add fast-xml-parser`
|
||||
|
||||
To use it from a **CLI** install it globally with the `-g` option.
|
||||
|
||||
`npm install fast-xml-parser -g`
|
||||
|
||||
To use it on a **webpage** include it from a [CDN](https://cdnjs.com/libraries/fast-xml-parser)
|
||||
|
||||
### XML to JSON
|
||||
|
||||
|
||||
```js
|
||||
const jsonObj = parser.parse(xmlData [,options] );
|
||||
```
|
||||
|
||||
```js
|
||||
const parser = require('fast-xml-parser');
|
||||
const he = require('he');
|
||||
|
||||
const options = {
|
||||
attributeNamePrefix : "@_",
|
||||
attrNodeName: "attr", //default is 'false'
|
||||
textNodeName : "#text",
|
||||
ignoreAttributes : true,
|
||||
ignoreNameSpace : false,
|
||||
allowBooleanAttributes : false,
|
||||
parseNodeValue : true,
|
||||
parseAttributeValue : false,
|
||||
trimValues: true,
|
||||
cdataTagName: "__cdata", //default is 'false'
|
||||
cdataPositionChar: "\\c",
|
||||
parseTrueNumberOnly: false,
|
||||
numParseOptions:{
|
||||
hex: true,
|
||||
leadingZeros: true,
|
||||
//skipLike: /\+[0-9]{10}/
|
||||
},
|
||||
arrayMode: false, //"strict"
|
||||
attrValueProcessor: (val, attrName) => he.decode(val, {isAttributeValue: true}),//default is a=>a
|
||||
tagValueProcessor : (val, tagName) => he.decode(val), //default is a=>a
|
||||
stopNodes: ["parse-me-as-string"],
|
||||
alwaysCreateTextNode: false
|
||||
};
|
||||
|
||||
if( parser.validate(xmlData) === true) { //optional (it'll return an object in case it's not valid)
|
||||
let jsonObj = parser.parse(xmlData,options);
|
||||
}
|
||||
|
||||
// Intermediate obj
|
||||
const tObj = parser.getTraversalObj(xmlData,options);
|
||||
let jsonObj = parser.convertToJson(tObj,options);
|
||||
|
||||
```
|
||||
As you can notice in the above code, validator is not embedded with in the parser and expected to be called separately. However, you can pass `true` or validation options as 3rd parameter to the parser to trigger validator internally. It is same as above example.
|
||||
|
||||
```js
|
||||
try{
|
||||
let jsonObj = parser.parse(xmlData,options, true);
|
||||
}catch(error){
|
||||
console.log(error.message)
|
||||
}
|
||||
```
|
||||
|
||||
Validator returns the following object in case of error;
|
||||
```js
|
||||
{
|
||||
err: {
|
||||
code: code,
|
||||
msg: message,
|
||||
line: lineNumber,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
#### Note: [he](https://www.npmjs.com/package/he) library is used in this example
|
||||
|
||||
<details>
|
||||
<summary>OPTIONS :</summary>
|
||||
|
||||
* **attributeNamePrefix** : prepend given string to attribute name for identification
|
||||
* **attrNodeName**: (Valid name) Group all the attributes as properties of given name.
|
||||
* **ignoreAttributes** : Ignore attributes to be parsed.
|
||||
* **ignoreNameSpace** : Remove namespace string from tag and attribute names.
|
||||
* **allowBooleanAttributes** : a tag can have attributes without any value
|
||||
* **parseNodeValue** : Parse the value of text node to float, integer, or boolean.
|
||||
* **parseAttributeValue** : Parse the value of an attribute to float, integer, or boolean.
|
||||
* **trimValues** : trim string values of an attribute or node
|
||||
* **decodeHTMLchar** : This options has been removed from 3.3.4. Instead, use tagValueProcessor, and attrValueProcessor. See above example.
|
||||
* **cdataTagName** : If specified, parser parse CDATA as nested tag instead of adding it's value to parent tag.
|
||||
* **cdataPositionChar** : It'll help to covert JSON back to XML without losing CDATA position.
|
||||
* **parseTrueNumberOnly**: if true then values like "+123", or "0123" will not be parsed as number.
|
||||
* **arrayMode** : When `false`, a tag with single occurrence is parsed as an object but as an array in case of multiple occurences. When `true`, a tag will be parsed as an array always excluding leaf nodes. When `strict`, all the tags will be parsed as array only. When instance of `RegEx`, only tags will be parsed as array that match the regex. When `function` a tag name is passed to the callback that can be checked.
|
||||
* **tagValueProcessor** : Process tag value during transformation. Like HTML decoding, word capitalization, etc. Applicable in case of string only.
|
||||
* **attrValueProcessor** : Process attribute value during transformation. Like HTML decoding, word capitalization, etc. Applicable in case of string only.
|
||||
* **stopNodes** : an array of tag names which are not required to be parsed. Instead their values are parsed as string.
|
||||
* **alwaysCreateTextNode** : When `true`, forces the parser always return a property for the `textNodeName` even if there are no attributes or node children.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>To use from <b>command line</b></summary>
|
||||
|
||||
```bash
|
||||
$xml2js [-ns|-a|-c|-v|-V] <filename> [-o outputfile.json]
|
||||
$cat xmlfile.xml | xml2js [-ns|-a|-c|-v|-V] [-o outputfile.json]
|
||||
```
|
||||
|
||||
* -ns : To include namespaces (by default ignored)
|
||||
* -a : To ignore attributes
|
||||
* -c : To ignore value conversion (i.e. "-3" will not be converted to number -3)
|
||||
* -v : validate before parsing
|
||||
* -V : only validate
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>To use it <b>on webpage</b></summary>
|
||||
|
||||
```js
|
||||
const result = parser.validate(xmlData);
|
||||
if (result !== true) console.log(result.err);
|
||||
const jsonObj = parser.parse(xmlData);
|
||||
```
|
||||
</details>
|
||||
|
||||
### JSON / JS Object to XML
|
||||
|
||||
```js
|
||||
const Parser = require("fast-xml-parser").j2xParser;
|
||||
//default options need not to set
|
||||
const defaultOptions = {
|
||||
attributeNamePrefix : "@_",
|
||||
attrNodeName: "@", //default is false
|
||||
textNodeName : "#text",
|
||||
ignoreAttributes : true,
|
||||
cdataTagName: "__cdata", //default is false
|
||||
cdataPositionChar: "\\c",
|
||||
format: false,
|
||||
indentBy: " ",
|
||||
supressEmptyNode: false,
|
||||
tagValueProcessor: a=> he.encode(a, { useNamedReferences: true}),// default is a=>a
|
||||
attrValueProcessor: a=> he.encode(a, {isAttributeValue: isAttribute, useNamedReferences: true}),// default is a=>a
|
||||
rootNodeName: "element"
|
||||
};
|
||||
const parser = new Parser(defaultOptions);
|
||||
const xml = parser.parse(json_or_js_obj);
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>OPTIONS :</summary>
|
||||
|
||||
With the correct options, you can get the almost original XML without losing any information.
|
||||
|
||||
* **attributeNamePrefix** : Identify attributes with this prefix otherwise treat them as a tag.
|
||||
* **attrNodeName**: Identify attributes when they are grouped under single property.
|
||||
* **ignoreAttributes** : Don't check for attributes. Treats everything as tag.
|
||||
* **encodeHTMLchar** : This option has been removed from 3.3.4. Use tagValueProcessor, and attrValueProcessor instead. See above example.
|
||||
* **cdataTagName** : If specified, parse matching tag as CDATA
|
||||
* **cdataPositionChar** : Identify the position where CDATA tag should be placed. If it is blank then CDATA will be added in the last of tag's value.
|
||||
* **format** : If set to true, then format the XML output.
|
||||
* **indentBy** : indent by this char `when` format is set to `true`
|
||||
* **supressEmptyNode** : If set to `true`, tags with no value (text or nested tags) are written as self closing tags.
|
||||
* **tagValueProcessor** : Process tag value during transformation. Like HTML encoding, word capitalization, etc. Applicable in case of string only.
|
||||
* **attrValueProcessor** : Process attribute value during transformation. Like HTML encoding, word capitalization, etc. Applicable in case of string only.
|
||||
* **rootNodeName** : When input js object is array, parser uses array index by default as tag name. You can set this property for proper response.
|
||||
</details>
|
||||
|
||||
## Benchmark
|
||||
|
||||
#### XML to JSON
|
||||
|
||||

|
||||
|
||||
<details>
|
||||
<summary>report</summary>
|
||||
|
||||
| file size | fxp 3.0 validator (rps) | fxp 3.0 parser (rps) | xml2js 0.4.19 (rps) |
|
||||
| ---------- | ----------------------- | ------------------- | ------------------- |
|
||||
| 1.5k | 16581.06758 | 14032.09323 | 4615.930805 |
|
||||
| 1.5m | 14918.47793 | 13.23366098 | 5.90682005 |
|
||||
| 13m | 1.834479235 | 1.135582008 | -1 |
|
||||
| 1.3k with CDATA | 30583.35319 | 43160.52342 | 8398.556349 |
|
||||
| 1.3m with CDATA | 27.29266471 | 52.68877009 | 7.966000795 |
|
||||
| 1.6k with cdata,prolog,doctype | 27690.26082 | 41433.98547 | 7872.399268 |
|
||||
| 98m | 0.08473858148 | 0.2600104004 | -1 |
|
||||
|
||||
* -1 indicates error or incorrect output.
|
||||
</details>
|
||||
|
||||
|
||||
#### JSON to XML
|
||||
|
||||

|
||||
|
||||
<details>
|
||||
<summary>report</summary>
|
||||
|
||||
| file size | fxp 3.2 js to xml | xml2js 0.4.19 builder |
|
||||
|------------|-----------------|-----------------|
|
||||
| 1.3k | 160148.9801 | 10384.99401|
|
||||
| 1.1m | 173.6374831 | 8.611884025|
|
||||
|
||||
</details>
|
||||
|
||||
### Worth to mention
|
||||
|
||||
- **[BigBit standard)](https://github.com/amitguptagwl/bigbit)** : A standard to represent any number in the universe in comparatively less space and without precision loss. A standard to save memory to represent any text string in comparision of UTF encodings.
|
||||
- **[imglab](https://github.com/NaturalIntelligence/imglab)** : Speedup and simplify image labeling / annotation. Supports multiple formats, one click annotation, easy interface and much more. There are more than half million images are being annotated every month using this tool.
|
||||
- [stubmatic](https://github.com/NaturalIntelligence/Stubmatic) : Create fake webservices, DynamoDB or S3 servers, Manage fake/mock stub data, Or fake any HTTP(s) call.
|
||||
- **[अनुमार्गक (anumargak)](https://github.com/NaturalIntelligence/anumargak)** : The fastest and simple router for node js web frameworks with many unique features.
|
||||
- [मुनीम (Muneem)](https://github.com/muneem4node/muneem) : A webframework made for all team members. Fast and Featured.
|
||||
- [शब्दावली (shabdawali)](https://github.com/amitguptagwl/shabdawali) : Amazing human like typing effects beyond your imagination.
|
||||
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
This project exists thanks to [all](graphs/contributors) the people who contribute. [[Contribute](docs/CONTRIBUTING.md)].
|
||||
<!-- <a href="graphs/contributors"><img src="https://opencollective.com/fast-xml-parser/contributors.svg?width=890&button=false" /></a> -->
|
||||
<!--
|
||||
### Lead Maintainers
|
||||

|
||||
[](https://github.com/Delagen)
|
||||
|
||||
### All Contributors -->
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/fast-xml-parser/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
## Backers
|
||||
|
||||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/fast-xml-parser#backer)]
|
||||
|
||||
<a href="https://opencollective.com/fast-xml-parser#backers" target="_blank"><img src="https://opencollective.com/fast-xml-parser/backers.svg?width=890"></a>
|
||||
|
||||
|
||||
## Sponsors
|
||||
|
||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/fast-xml-parser#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/0/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/1/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/2/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/3/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/4/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/5/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/6/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/7/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/8/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/fast-xml-parser/sponsor/9/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/9/avatar.svg"></a>
|
||||
|
||||
# License
|
||||
|
||||
* MIT License
|
||||
101
node_modules/fast-xml-parser/cli.js
generated
vendored
101
node_modules/fast-xml-parser/cli.js
generated
vendored
@@ -1,101 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
/*eslint-disable no-console*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const parser = require('./src/parser');
|
||||
const readToEnd = require('./src/read').readToEnd;
|
||||
|
||||
if (process.argv[2] === '--help' || process.argv[2] === '-h') {
|
||||
console.log('Fast XML Parser ' + require(path.join(__dirname + '/package.json')).version);
|
||||
console.log('----------------');
|
||||
console.log('xml2js [-ns|-a|-c|-v|-V] <filename> [-o outputfile.json]');
|
||||
console.log('cat xmlfile.xml | xml2js [-ns|-a|-c|-v|-V] [-o outputfile.json]');
|
||||
console.log('-ns: remove namespace from tag and atrribute name.');
|
||||
console.log("-a: don't parse attributes.");
|
||||
console.log('-c: parse values to premitive type.');
|
||||
console.log('-v: validate before parsing.');
|
||||
console.log('-V: validate only.');
|
||||
} else if (process.argv[2] === '--version') {
|
||||
console.log(require(path.join(__dirname + '/package.json')).version);
|
||||
} else {
|
||||
const options = {
|
||||
ignoreNameSpace: true,
|
||||
ignoreAttributes: false,
|
||||
parseNodeValue: 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.ignoreNameSpace = false;
|
||||
} else if (process.argv[i] === '-a') {
|
||||
options.ignoreAttributes = true;
|
||||
} else if (process.argv[i] === '-c') {
|
||||
options.parseNodeValue = 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 result = parser.validate(xmlData);
|
||||
if (result === true) {
|
||||
output = JSON.stringify(parser.parse(xmlData, options), null, 4);
|
||||
} else {
|
||||
output = result;
|
||||
}
|
||||
} else if (validateOnly) {
|
||||
output = parser.validate(xmlData);
|
||||
process.exitCode = output === true ? 0 : 1;
|
||||
} else {
|
||||
output = JSON.stringify(parser.parse(xmlData, options), null, 4);
|
||||
}
|
||||
if (outputFileName) {
|
||||
writeToFile(outputFileName, output);
|
||||
} else {
|
||||
console.log(output);
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
94
node_modules/fast-xml-parser/package.json
generated
vendored
94
node_modules/fast-xml-parser/package.json
generated
vendored
@@ -1,94 +0,0 @@
|
||||
{
|
||||
"name": "fast-xml-parser",
|
||||
"version": "3.21.1",
|
||||
"description": "Validate XML or Parse XML to JS/JSON very fast without C/C++ based libraries",
|
||||
"main": "./src/parser.js",
|
||||
"scripts": {
|
||||
"test": "nyc --reporter=lcov --reporter=text jasmine spec/*spec.js",
|
||||
"unit": "jasmine",
|
||||
"coverage": "nyc report --reporter html --reporter text -t .nyc_output --report-dir .nyc_output/summary",
|
||||
"perf": "node ./benchmark/perfTest3.js",
|
||||
"lint": "eslint src/*.js spec/*.js",
|
||||
"bundle": "webpack && webpack --config webpack-prod.config.js",
|
||||
"prettier": "prettier --write src/**/*.js",
|
||||
"publish-please": "publish-please",
|
||||
"checkReadiness": "publish-please --dry-run"
|
||||
},
|
||||
"bin": {
|
||||
"xml2js": "./cli.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/NaturalIntelligence/fast-xml-parser"
|
||||
},
|
||||
"keywords": [
|
||||
"fast",
|
||||
"xml",
|
||||
"json",
|
||||
"parser",
|
||||
"xml2js",
|
||||
"x2js",
|
||||
"xml2json",
|
||||
"js",
|
||||
"traversable",
|
||||
"cli",
|
||||
"command",
|
||||
"validator",
|
||||
"validate",
|
||||
"transformer",
|
||||
"checker",
|
||||
"assert",
|
||||
"big",
|
||||
"js2xml",
|
||||
"json2xml",
|
||||
"nimn",
|
||||
"xml2nimn",
|
||||
"locale",
|
||||
"html"
|
||||
],
|
||||
"author": "Amit Gupta (https://amitkumargupta.work/)",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Alfonso Muñoz-Pomer Fuentes",
|
||||
"email": "amunoz@ebi.ac.uk",
|
||||
"url": "https://github.com/alfonsomunozpomer"
|
||||
},
|
||||
{
|
||||
"name": "Steve Reichenbach",
|
||||
"url": "https://github.com/EyesOnlyNet"
|
||||
},
|
||||
{
|
||||
"name": "Vohmyanin Sergey Vasilevich",
|
||||
"url": "http://delagen.livejournal.com"
|
||||
},
|
||||
{
|
||||
"name": "Andrew Udvare",
|
||||
"url": "https://github.com/Tatsh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.13.10",
|
||||
"@babel/plugin-transform-runtime": "^7.13.10",
|
||||
"@babel/preset-env": "^7.13.10",
|
||||
"@babel/register": "^7.13.8",
|
||||
"babel-loader": "^8.2.2",
|
||||
"eslint": "^5.16.0",
|
||||
"he": "^1.2.0",
|
||||
"jasmine": "^3.6.4",
|
||||
"nimnjs": "^1.3.2",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^1.19.1",
|
||||
"publish-please": "^5.5.2",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-cli": "^3.3.12"
|
||||
},
|
||||
"typings": "src/parser.d.ts",
|
||||
"funding": {
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
},
|
||||
"dependencies": {
|
||||
"strnum": "^1.0.4"
|
||||
}
|
||||
}
|
||||
280
node_modules/fast-xml-parser/src/json2xml.js
generated
vendored
280
node_modules/fast-xml-parser/src/json2xml.js
generated
vendored
@@ -1,280 +0,0 @@
|
||||
'use strict';
|
||||
//parse Empty Node as self closing node
|
||||
const buildOptions = require('./util').buildOptions;
|
||||
|
||||
const defaultOptions = {
|
||||
attributeNamePrefix: '@_',
|
||||
attrNodeName: false,
|
||||
textNodeName: '#text',
|
||||
ignoreAttributes: true,
|
||||
cdataTagName: false,
|
||||
cdataPositionChar: '\\c',
|
||||
format: false,
|
||||
indentBy: ' ',
|
||||
supressEmptyNode: false,
|
||||
tagValueProcessor: function(a) {
|
||||
return a;
|
||||
},
|
||||
attrValueProcessor: function(a) {
|
||||
return a;
|
||||
},
|
||||
};
|
||||
|
||||
const props = [
|
||||
'attributeNamePrefix',
|
||||
'attrNodeName',
|
||||
'textNodeName',
|
||||
'ignoreAttributes',
|
||||
'cdataTagName',
|
||||
'cdataPositionChar',
|
||||
'format',
|
||||
'indentBy',
|
||||
'supressEmptyNode',
|
||||
'tagValueProcessor',
|
||||
'attrValueProcessor',
|
||||
'rootNodeName', //when array as root
|
||||
];
|
||||
|
||||
function Parser(options) {
|
||||
this.options = buildOptions(options, defaultOptions, props);
|
||||
if (this.options.ignoreAttributes || this.options.attrNodeName) {
|
||||
this.isAttribute = function(/*a*/) {
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
this.attrPrefixLen = this.options.attributeNamePrefix.length;
|
||||
this.isAttribute = isAttribute;
|
||||
}
|
||||
if (this.options.cdataTagName) {
|
||||
this.isCDATA = isCDATA;
|
||||
} else {
|
||||
this.isCDATA = function(/*a*/) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
this.replaceCDATAstr = replaceCDATAstr;
|
||||
this.replaceCDATAarr = replaceCDATAarr;
|
||||
|
||||
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 = '';
|
||||
}
|
||||
|
||||
if (this.options.supressEmptyNode) {
|
||||
this.buildTextNode = buildEmptyTextNode;
|
||||
this.buildObjNode = buildEmptyObjNode;
|
||||
} else {
|
||||
this.buildTextNode = buildTextValNode;
|
||||
this.buildObjNode = buildObjectNode;
|
||||
}
|
||||
|
||||
this.buildTextValNode = buildTextValNode;
|
||||
this.buildObjectNode = buildObjectNode;
|
||||
}
|
||||
|
||||
Parser.prototype.parse = function(jObj) {
|
||||
if(Array.isArray(jObj) && this.options.rootNodeName && this.options.rootNodeName.length > 1){
|
||||
jObj = {
|
||||
[this.options.rootNodeName] : jObj
|
||||
}
|
||||
}
|
||||
return this.j2x(jObj, 0).val;
|
||||
};
|
||||
|
||||
Parser.prototype.j2x = function(jObj, level) {
|
||||
let attrStr = '';
|
||||
let val = '';
|
||||
for (let key in jObj) {
|
||||
if (typeof jObj[key] === 'undefined') {
|
||||
// supress undefined node
|
||||
} else if (jObj[key] === null) {
|
||||
val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
} else if (jObj[key] instanceof Date) {
|
||||
val += this.buildTextNode(jObj[key], key, '', level);
|
||||
} else if (typeof jObj[key] !== 'object') {
|
||||
//premitive type
|
||||
const attr = this.isAttribute(key);
|
||||
if (attr) {
|
||||
attrStr += ' ' + attr + '="' + this.options.attrValueProcessor('' + jObj[key]) + '"';
|
||||
} else if (this.isCDATA(key)) {
|
||||
if (jObj[this.options.textNodeName]) {
|
||||
val += this.replaceCDATAstr(jObj[this.options.textNodeName], jObj[key]);
|
||||
} else {
|
||||
val += this.replaceCDATAstr('', jObj[key]);
|
||||
}
|
||||
} else {
|
||||
//tag value
|
||||
if (key === this.options.textNodeName) {
|
||||
if (jObj[this.options.cdataTagName]) {
|
||||
//value will added while processing cdata
|
||||
} else {
|
||||
val += this.options.tagValueProcessor('' + jObj[key]);
|
||||
}
|
||||
} else {
|
||||
val += this.buildTextNode(jObj[key], key, '', level);
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(jObj[key])) {
|
||||
//repeated nodes
|
||||
if (this.isCDATA(key)) {
|
||||
val += this.indentate(level);
|
||||
if (jObj[this.options.textNodeName]) {
|
||||
val += this.replaceCDATAarr(jObj[this.options.textNodeName], jObj[key]);
|
||||
} else {
|
||||
val += this.replaceCDATAarr('', jObj[key]);
|
||||
}
|
||||
} else {
|
||||
//nested nodes
|
||||
const arrLen = jObj[key].length;
|
||||
for (let j = 0; j < arrLen; j++) {
|
||||
const item = jObj[key][j];
|
||||
if (typeof item === 'undefined') {
|
||||
// supress undefined node
|
||||
} else if (item === null) {
|
||||
val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
||||
} else if (typeof item === 'object') {
|
||||
val += this.processTextOrObjNode(item, key, level)
|
||||
} else {
|
||||
val += this.buildTextNode(item, key, '', level);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//nested node
|
||||
if (this.options.attrNodeName && key === this.options.attrNodeName) {
|
||||
const Ks = Object.keys(jObj[key]);
|
||||
const L = Ks.length;
|
||||
for (let j = 0; j < L; j++) {
|
||||
attrStr += ' ' + Ks[j] + '="' + this.options.attrValueProcessor('' + jObj[key][Ks[j]]) + '"';
|
||||
}
|
||||
} else {
|
||||
val += this.processTextOrObjNode(jObj[key], key, level)
|
||||
}
|
||||
}
|
||||
}
|
||||
return {attrStr: attrStr, val: val};
|
||||
};
|
||||
|
||||
function processTextOrObjNode (object, key, level) {
|
||||
const result = this.j2x(object, level + 1);
|
||||
if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
|
||||
return this.buildTextNode(result.val, key, result.attrStr, level);
|
||||
} else {
|
||||
return this.buildObjNode(result.val, key, result.attrStr, level);
|
||||
}
|
||||
}
|
||||
|
||||
function replaceCDATAstr(str, cdata) {
|
||||
str = this.options.tagValueProcessor('' + str);
|
||||
if (this.options.cdataPositionChar === '' || str === '') {
|
||||
return str + '<![CDATA[' + cdata + ']]' + this.tagEndChar;
|
||||
} else {
|
||||
return str.replace(this.options.cdataPositionChar, '<![CDATA[' + cdata + ']]' + this.tagEndChar);
|
||||
}
|
||||
}
|
||||
|
||||
function replaceCDATAarr(str, cdata) {
|
||||
str = this.options.tagValueProcessor('' + str);
|
||||
if (this.options.cdataPositionChar === '' || str === '') {
|
||||
return str + '<![CDATA[' + cdata.join(']]><![CDATA[') + ']]' + this.tagEndChar;
|
||||
} else {
|
||||
for (let v in cdata) {
|
||||
str = str.replace(this.options.cdataPositionChar, '<![CDATA[' + cdata[v] + ']]>');
|
||||
}
|
||||
return str + this.newLine;
|
||||
}
|
||||
}
|
||||
|
||||
function buildObjectNode(val, key, attrStr, level) {
|
||||
if (attrStr && val.indexOf('<') === -1) {
|
||||
return (
|
||||
this.indentate(level) +
|
||||
'<' +
|
||||
key +
|
||||
attrStr +
|
||||
'>' +
|
||||
val +
|
||||
//+ this.newLine
|
||||
// + this.indentate(level)
|
||||
'</' +
|
||||
key +
|
||||
this.tagEndChar
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
this.indentate(level) +
|
||||
'<' +
|
||||
key +
|
||||
attrStr +
|
||||
this.tagEndChar +
|
||||
val +
|
||||
//+ this.newLine
|
||||
this.indentate(level) +
|
||||
'</' +
|
||||
key +
|
||||
this.tagEndChar
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function buildEmptyObjNode(val, key, attrStr, level) {
|
||||
if (val !== '') {
|
||||
return this.buildObjectNode(val, key, attrStr, level);
|
||||
} else {
|
||||
return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
|
||||
//+ this.newLine
|
||||
}
|
||||
}
|
||||
|
||||
function buildTextValNode(val, key, attrStr, level) {
|
||||
return (
|
||||
this.indentate(level) +
|
||||
'<' +
|
||||
key +
|
||||
attrStr +
|
||||
'>' +
|
||||
this.options.tagValueProcessor(val) +
|
||||
'</' +
|
||||
key +
|
||||
this.tagEndChar
|
||||
);
|
||||
}
|
||||
|
||||
function buildEmptyTextNode(val, key, attrStr, level) {
|
||||
if (val !== '') {
|
||||
return this.buildTextValNode(val, key, attrStr, level);
|
||||
} else {
|
||||
return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
|
||||
}
|
||||
}
|
||||
|
||||
function indentate(level) {
|
||||
return this.options.indentBy.repeat(level);
|
||||
}
|
||||
|
||||
function isAttribute(name /*, options*/) {
|
||||
if (name.startsWith(this.options.attributeNamePrefix)) {
|
||||
return name.substr(this.attrPrefixLen);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isCDATA(name) {
|
||||
return name === this.options.cdataTagName;
|
||||
}
|
||||
|
||||
//formatting
|
||||
//indentation
|
||||
//\n after each closing or self closing tag
|
||||
|
||||
module.exports = Parser;
|
||||
144
node_modules/fast-xml-parser/src/nimndata.js
generated
vendored
144
node_modules/fast-xml-parser/src/nimndata.js
generated
vendored
@@ -1,144 +0,0 @@
|
||||
'use strict';
|
||||
const char = function(a) {
|
||||
return String.fromCharCode(a);
|
||||
};
|
||||
|
||||
const chars = {
|
||||
nilChar: char(176),
|
||||
missingChar: char(201),
|
||||
nilPremitive: char(175),
|
||||
missingPremitive: char(200),
|
||||
|
||||
emptyChar: char(178),
|
||||
emptyValue: char(177), //empty Premitive
|
||||
|
||||
boundryChar: char(179),
|
||||
|
||||
objStart: char(198),
|
||||
arrStart: char(204),
|
||||
arrayEnd: char(185),
|
||||
};
|
||||
|
||||
const charsArr = [
|
||||
chars.nilChar,
|
||||
chars.nilPremitive,
|
||||
chars.missingChar,
|
||||
chars.missingPremitive,
|
||||
chars.boundryChar,
|
||||
chars.emptyChar,
|
||||
chars.emptyValue,
|
||||
chars.arrayEnd,
|
||||
chars.objStart,
|
||||
chars.arrStart,
|
||||
];
|
||||
|
||||
const _e = function(node, e_schema, options) {
|
||||
if (typeof e_schema === 'string') {
|
||||
//premitive
|
||||
if (node && node[0] && node[0].val !== undefined) {
|
||||
return getValue(node[0].val, e_schema);
|
||||
} else {
|
||||
return getValue(node, e_schema);
|
||||
}
|
||||
} else {
|
||||
const hasValidData = hasData(node);
|
||||
if (hasValidData === true) {
|
||||
let str = '';
|
||||
if (Array.isArray(e_schema)) {
|
||||
//attributes can't be repeated. hence check in children tags only
|
||||
str += chars.arrStart;
|
||||
const itemSchema = e_schema[0];
|
||||
//const itemSchemaType = itemSchema;
|
||||
const arr_len = node.length;
|
||||
|
||||
if (typeof itemSchema === 'string') {
|
||||
for (let arr_i = 0; arr_i < arr_len; arr_i++) {
|
||||
const r = getValue(node[arr_i].val, itemSchema);
|
||||
str = processValue(str, r);
|
||||
}
|
||||
} else {
|
||||
for (let arr_i = 0; arr_i < arr_len; arr_i++) {
|
||||
const r = _e(node[arr_i], itemSchema, options);
|
||||
str = processValue(str, r);
|
||||
}
|
||||
}
|
||||
str += chars.arrayEnd; //indicates that next item is not array item
|
||||
} else {
|
||||
//object
|
||||
str += chars.objStart;
|
||||
const keys = Object.keys(e_schema);
|
||||
if (Array.isArray(node)) {
|
||||
node = node[0];
|
||||
}
|
||||
for (let i in keys) {
|
||||
const key = keys[i];
|
||||
//a property defined in schema can be present either in attrsMap or children tags
|
||||
//options.textNodeName will not present in both maps, take it's value from val
|
||||
//options.attrNodeName will be present in attrsMap
|
||||
let r;
|
||||
if (!options.ignoreAttributes && node.attrsMap && node.attrsMap[key]) {
|
||||
r = _e(node.attrsMap[key], e_schema[key], options);
|
||||
} else if (key === options.textNodeName) {
|
||||
r = _e(node.val, e_schema[key], options);
|
||||
} else {
|
||||
r = _e(node.child[key], e_schema[key], options);
|
||||
}
|
||||
str = processValue(str, r);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
} else {
|
||||
return hasValidData;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getValue = function(a /*, type*/) {
|
||||
switch (a) {
|
||||
case undefined:
|
||||
return chars.missingPremitive;
|
||||
case null:
|
||||
return chars.nilPremitive;
|
||||
case '':
|
||||
return chars.emptyValue;
|
||||
default:
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
const processValue = function(str, r) {
|
||||
if (!isAppChar(r[0]) && !isAppChar(str[str.length - 1])) {
|
||||
str += chars.boundryChar;
|
||||
}
|
||||
return str + r;
|
||||
};
|
||||
|
||||
const isAppChar = function(ch) {
|
||||
return charsArr.indexOf(ch) !== -1;
|
||||
};
|
||||
|
||||
function hasData(jObj) {
|
||||
if (jObj === undefined) {
|
||||
return chars.missingChar;
|
||||
} else if (jObj === null) {
|
||||
return chars.nilChar;
|
||||
} else if (
|
||||
jObj.child &&
|
||||
Object.keys(jObj.child).length === 0 &&
|
||||
(!jObj.attrsMap || Object.keys(jObj.attrsMap).length === 0)
|
||||
) {
|
||||
return chars.emptyChar;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const x2j = require('./xmlstr2xmlnode');
|
||||
const buildOptions = require('./util').buildOptions;
|
||||
|
||||
const convert2nimn = function(node, e_schema, options) {
|
||||
options = buildOptions(options, x2j.defaultOptions, x2j.props);
|
||||
return _e(node, e_schema, options);
|
||||
};
|
||||
|
||||
exports.convert2nimn = convert2nimn;
|
||||
42
node_modules/fast-xml-parser/src/node2json.js
generated
vendored
42
node_modules/fast-xml-parser/src/node2json.js
generated
vendored
@@ -1,42 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('./util');
|
||||
|
||||
const convertToJson = function(node, options, parentTagName) {
|
||||
const jObj = {};
|
||||
|
||||
// when no child node or attr is present
|
||||
if (!options.alwaysCreateTextNode && (!node.child || util.isEmptyObject(node.child)) && (!node.attrsMap || util.isEmptyObject(node.attrsMap))) {
|
||||
return util.isExist(node.val) ? node.val : '';
|
||||
}
|
||||
|
||||
// otherwise create a textnode if node has some text
|
||||
if (util.isExist(node.val) && !(typeof node.val === 'string' && (node.val === '' || node.val === options.cdataPositionChar))) {
|
||||
const asArray = util.isTagNameInArrayMode(node.tagname, options.arrayMode, parentTagName)
|
||||
jObj[options.textNodeName] = asArray ? [node.val] : node.val;
|
||||
}
|
||||
|
||||
util.merge(jObj, node.attrsMap, options.arrayMode);
|
||||
|
||||
const keys = Object.keys(node.child);
|
||||
for (let index = 0; index < keys.length; index++) {
|
||||
const tagName = keys[index];
|
||||
if (node.child[tagName] && node.child[tagName].length > 1) {
|
||||
jObj[tagName] = [];
|
||||
for (let tag in node.child[tagName]) {
|
||||
if (node.child[tagName].hasOwnProperty(tag)) {
|
||||
jObj[tagName].push(convertToJson(node.child[tagName][tag], options, tagName));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const result = convertToJson(node.child[tagName][0], options, tagName);
|
||||
const asArray = (options.arrayMode === true && typeof result === 'object') || util.isTagNameInArrayMode(tagName, options.arrayMode, parentTagName);
|
||||
jObj[tagName] = asArray ? [result] : result;
|
||||
}
|
||||
}
|
||||
|
||||
//add value
|
||||
return jObj;
|
||||
};
|
||||
|
||||
exports.convertToJson = convertToJson;
|
||||
63
node_modules/fast-xml-parser/src/node2json_str.js
generated
vendored
63
node_modules/fast-xml-parser/src/node2json_str.js
generated
vendored
@@ -1,63 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('./util');
|
||||
const buildOptions = require('./util').buildOptions;
|
||||
const x2j = require('./xmlstr2xmlnode');
|
||||
|
||||
//TODO: do it later
|
||||
const convertToJsonString = function(node, options) {
|
||||
options = buildOptions(options, x2j.defaultOptions, x2j.props);
|
||||
|
||||
options.indentBy = options.indentBy || '';
|
||||
return _cToJsonStr(node, options, 0);
|
||||
};
|
||||
|
||||
const _cToJsonStr = function(node, options, level) {
|
||||
let jObj = '{';
|
||||
|
||||
//traver through all the children
|
||||
const keys = Object.keys(node.child);
|
||||
|
||||
for (let index = 0; index < keys.length; index++) {
|
||||
const tagname = keys[index];
|
||||
if (node.child[tagname] && node.child[tagname].length > 1) {
|
||||
jObj += '"' + tagname + '" : [ ';
|
||||
for (let tag in node.child[tagname]) {
|
||||
jObj += _cToJsonStr(node.child[tagname][tag], options) + ' , ';
|
||||
}
|
||||
jObj = jObj.substr(0, jObj.length - 1) + ' ] '; //remove extra comma in last
|
||||
} else {
|
||||
jObj += '"' + tagname + '" : ' + _cToJsonStr(node.child[tagname][0], options) + ' ,';
|
||||
}
|
||||
}
|
||||
util.merge(jObj, node.attrsMap);
|
||||
//add attrsMap as new children
|
||||
if (util.isEmptyObject(jObj)) {
|
||||
return util.isExist(node.val) ? node.val : '';
|
||||
} else {
|
||||
if (util.isExist(node.val)) {
|
||||
if (!(typeof node.val === 'string' && (node.val === '' || node.val === options.cdataPositionChar))) {
|
||||
jObj += '"' + options.textNodeName + '" : ' + stringval(node.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
//add value
|
||||
if (jObj[jObj.length - 1] === ',') {
|
||||
jObj = jObj.substr(0, jObj.length - 2);
|
||||
}
|
||||
return jObj + '}';
|
||||
};
|
||||
|
||||
function stringval(v) {
|
||||
if (v === true || v === false || !isNaN(v)) {
|
||||
return v;
|
||||
} else {
|
||||
return '"' + v + '"';
|
||||
}
|
||||
}
|
||||
|
||||
function indentate(options, level) {
|
||||
return options.indentBy.repeat(level);
|
||||
}
|
||||
|
||||
exports.convertToJsonString = convertToJsonString;
|
||||
79
node_modules/fast-xml-parser/src/parser.d.ts
generated
vendored
79
node_modules/fast-xml-parser/src/parser.d.ts
generated
vendored
@@ -1,79 +0,0 @@
|
||||
type X2jOptions = {
|
||||
attributeNamePrefix: string;
|
||||
attrNodeName: false | string;
|
||||
textNodeName: string;
|
||||
ignoreAttributes: boolean;
|
||||
ignoreNameSpace: boolean;
|
||||
allowBooleanAttributes: boolean;
|
||||
parseNodeValue: boolean;
|
||||
parseAttributeValue: boolean;
|
||||
arrayMode: boolean | 'strict' | RegExp | ((tagName: string, parentTagName: string) => boolean);
|
||||
trimValues: boolean;
|
||||
cdataTagName: false | string;
|
||||
cdataPositionChar: string;
|
||||
parseTrueNumberOnly: boolean;
|
||||
numParseOptions: strnumOptions;
|
||||
tagValueProcessor: (tagValue: string, tagName: string) => string;
|
||||
attrValueProcessor: (attrValue: string, attrName: string) => string;
|
||||
stopNodes: string[];
|
||||
alwaysCreateTextNode: boolean;
|
||||
};
|
||||
type strnumOptions = {
|
||||
hex: boolean;
|
||||
leadingZeros: boolean,
|
||||
skipLike?: RegExp
|
||||
}
|
||||
type X2jOptionsOptional = Partial<X2jOptions>;
|
||||
type validationOptions = {
|
||||
allowBooleanAttributes: boolean;
|
||||
};
|
||||
type validationOptionsOptional = Partial<validationOptions>;
|
||||
type J2xOptions = {
|
||||
attributeNamePrefix: string;
|
||||
attrNodeName: false | string;
|
||||
textNodeName: string;
|
||||
ignoreAttributes: boolean;
|
||||
cdataTagName: false | string;
|
||||
cdataPositionChar: string;
|
||||
format: boolean;
|
||||
indentBy: string;
|
||||
supressEmptyNode: boolean;
|
||||
tagValueProcessor: (tagValue: string) => string;
|
||||
attrValueProcessor: (attrValue: string) => string;
|
||||
};
|
||||
type J2xOptionsOptional = Partial<J2xOptions>;
|
||||
|
||||
type ESchema = string | object | Array<string|object>;
|
||||
|
||||
type ValidationError = {
|
||||
err: { code: string; msg: string, line: number, col: number };
|
||||
};
|
||||
|
||||
export function parse(xmlData: string, options?: X2jOptionsOptional, validationOptions?: validationOptionsOptional | boolean): any;
|
||||
export function convert2nimn(
|
||||
node: any,
|
||||
e_schema: ESchema,
|
||||
options?: X2jOptionsOptional
|
||||
): any;
|
||||
export function getTraversalObj(
|
||||
xmlData: string,
|
||||
options?: X2jOptionsOptional
|
||||
): any;
|
||||
export function convertToJson(node: any, options?: X2jOptionsOptional): any;
|
||||
export function convertToJsonString(
|
||||
node: any,
|
||||
options?: X2jOptionsOptional
|
||||
): string;
|
||||
export function validate(
|
||||
xmlData: string,
|
||||
options?: validationOptionsOptional
|
||||
): true | ValidationError;
|
||||
export class j2xParser {
|
||||
constructor(options: J2xOptionsOptional);
|
||||
parse(options: any): any;
|
||||
}
|
||||
export function parseToNimn(
|
||||
xmlData: string,
|
||||
schema: any,
|
||||
options: Partial<X2jOptions>
|
||||
): any;
|
||||
76
node_modules/fast-xml-parser/src/parser.js
generated
vendored
76
node_modules/fast-xml-parser/src/parser.js
generated
vendored
@@ -1,76 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const nodeToJson = require('./node2json');
|
||||
const xmlToNodeobj = require('./xmlstr2xmlnode');
|
||||
const x2xmlnode = require('./xmlstr2xmlnode');
|
||||
const buildOptions = require('./util').buildOptions;
|
||||
const validator = require('./validator');
|
||||
|
||||
exports.parse = function(xmlData, givenOptions = {}, validationOption) {
|
||||
if( validationOption){
|
||||
if(validationOption === true) validationOption = {}
|
||||
|
||||
const result = validator.validate(xmlData, validationOption);
|
||||
if (result !== true) {
|
||||
throw Error( result.err.msg)
|
||||
}
|
||||
}
|
||||
if(givenOptions.parseTrueNumberOnly
|
||||
&& givenOptions.parseNodeValue !== false
|
||||
&& !givenOptions.numParseOptions){
|
||||
|
||||
givenOptions.numParseOptions = {
|
||||
leadingZeros: false,
|
||||
}
|
||||
}
|
||||
let options = buildOptions(givenOptions, x2xmlnode.defaultOptions, x2xmlnode.props);
|
||||
|
||||
const traversableObj = xmlToNodeobj.getTraversalObj(xmlData, options)
|
||||
//print(traversableObj, " ");
|
||||
return nodeToJson.convertToJson(traversableObj, options);
|
||||
};
|
||||
exports.convertTonimn = require('./nimndata').convert2nimn;
|
||||
exports.getTraversalObj = xmlToNodeobj.getTraversalObj;
|
||||
exports.convertToJson = nodeToJson.convertToJson;
|
||||
exports.convertToJsonString = require('./node2json_str').convertToJsonString;
|
||||
exports.validate = validator.validate;
|
||||
exports.j2xParser = require('./json2xml');
|
||||
exports.parseToNimn = function(xmlData, schema, options) {
|
||||
return exports.convertTonimn(exports.getTraversalObj(xmlData, options), schema, options);
|
||||
};
|
||||
|
||||
|
||||
function print(xmlNode, indentation){
|
||||
if(xmlNode){
|
||||
console.log(indentation + "{")
|
||||
console.log(indentation + " \"tagName\": \"" + xmlNode.tagname + "\", ");
|
||||
if(xmlNode.parent){
|
||||
console.log(indentation + " \"parent\": \"" + xmlNode.parent.tagname + "\", ");
|
||||
}
|
||||
console.log(indentation + " \"val\": \"" + xmlNode.val + "\", ");
|
||||
console.log(indentation + " \"attrs\": " + JSON.stringify(xmlNode.attrsMap,null,4) + ", ");
|
||||
|
||||
if(xmlNode.child){
|
||||
console.log(indentation + "\"child\": {")
|
||||
const indentation2 = indentation + indentation;
|
||||
Object.keys(xmlNode.child).forEach( function(key) {
|
||||
const node = xmlNode.child[key];
|
||||
|
||||
if(Array.isArray(node)){
|
||||
console.log(indentation + "\""+key+"\" :[")
|
||||
node.forEach( function(item,index) {
|
||||
//console.log(indentation + " \""+index+"\" : [")
|
||||
print(item, indentation2);
|
||||
})
|
||||
console.log(indentation + "],")
|
||||
}else{
|
||||
console.log(indentation + " \""+key+"\" : {")
|
||||
print(node, indentation2);
|
||||
console.log(indentation + "},")
|
||||
}
|
||||
});
|
||||
console.log(indentation + "},")
|
||||
}
|
||||
console.log(indentation + "},")
|
||||
}
|
||||
}
|
||||
92
node_modules/fast-xml-parser/src/read.js
generated
vendored
92
node_modules/fast-xml-parser/src/read.js
generated
vendored
@@ -1,92 +0,0 @@
|
||||
'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;
|
||||
};
|
||||
108
node_modules/fast-xml-parser/src/util.js
generated
vendored
108
node_modules/fast-xml-parser/src/util.js
generated
vendored
@@ -1,108 +0,0 @@
|
||||
'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.buildOptions = function(options, defaultOptions, props) {
|
||||
let newOptions = {};
|
||||
if (!options) {
|
||||
return defaultOptions; //if there are not options
|
||||
}
|
||||
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
if (options[props[i]] !== undefined) {
|
||||
newOptions[props[i]] = options[props[i]];
|
||||
} else {
|
||||
newOptions[props[i]] = defaultOptions[props[i]];
|
||||
}
|
||||
}
|
||||
return newOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a tag name should be treated as array
|
||||
*
|
||||
* @param tagName the node tagname
|
||||
* @param arrayMode the array mode option
|
||||
* @param parentTagName the parent tag name
|
||||
* @returns {boolean} true if node should be parsed as array
|
||||
*/
|
||||
exports.isTagNameInArrayMode = function (tagName, arrayMode, parentTagName) {
|
||||
if (arrayMode === false) {
|
||||
return false;
|
||||
} else if (arrayMode instanceof RegExp) {
|
||||
return arrayMode.test(tagName);
|
||||
} else if (typeof arrayMode === 'function') {
|
||||
return !!arrayMode(tagName, parentTagName);
|
||||
}
|
||||
|
||||
return arrayMode === "strict";
|
||||
}
|
||||
|
||||
exports.isName = isName;
|
||||
exports.getAllMatches = getAllMatches;
|
||||
exports.nameRegexp = nameRegexp;
|
||||
413
node_modules/fast-xml-parser/src/validator.js
generated
vendored
413
node_modules/fast-xml-parser/src/validator.js
generated
vendored
@@ -1,413 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('./util');
|
||||
|
||||
const defaultOptions = {
|
||||
allowBooleanAttributes: false, //A tag can have attributes without any value
|
||||
};
|
||||
|
||||
const props = ['allowBooleanAttributes'];
|
||||
|
||||
//const tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g");
|
||||
exports.validate = function (xmlData, options) {
|
||||
options = util.buildOptions(options, defaultOptions, props);
|
||||
|
||||
//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 {
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
} //end of reading tag text value
|
||||
if (xmlData[i] === '<') {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (xmlData[i] === ' ' || xmlData[i] === '\t' || xmlData[i] === '\n' || xmlData[i] === '\r') {
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 && !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;
|
||||
}
|
||||
17
node_modules/fast-xml-parser/src/xmlNode.js
generated
vendored
17
node_modules/fast-xml-parser/src/xmlNode.js
generated
vendored
@@ -1,17 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function(tagname, parent, val) {
|
||||
this.tagname = tagname;
|
||||
this.parent = parent;
|
||||
this.child = {}; //child tags
|
||||
this.attrsMap = {}; //attributes map
|
||||
this.val = val; //text only
|
||||
this.addChild = function(child) {
|
||||
if (Array.isArray(this.child[child.tagname])) {
|
||||
//already presents
|
||||
this.child[child.tagname].push(child);
|
||||
} else {
|
||||
this.child[child.tagname] = [child];
|
||||
}
|
||||
};
|
||||
};
|
||||
339
node_modules/fast-xml-parser/src/xmlstr2xmlnode.js
generated
vendored
339
node_modules/fast-xml-parser/src/xmlstr2xmlnode.js
generated
vendored
@@ -1,339 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('./util');
|
||||
const buildOptions = require('./util').buildOptions;
|
||||
const xmlNode = require('./xmlNode');
|
||||
const toNumber = require("strnum");
|
||||
|
||||
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");
|
||||
|
||||
//polyfill
|
||||
if (!Number.parseInt && window.parseInt) {
|
||||
Number.parseInt = window.parseInt;
|
||||
}
|
||||
if (!Number.parseFloat && window.parseFloat) {
|
||||
Number.parseFloat = window.parseFloat;
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
attributeNamePrefix: '@_',
|
||||
attrNodeName: false,
|
||||
textNodeName: '#text',
|
||||
ignoreAttributes: true,
|
||||
ignoreNameSpace: false,
|
||||
allowBooleanAttributes: false, //a tag can have attributes without any value
|
||||
//ignoreRootElement : false,
|
||||
parseNodeValue: true,
|
||||
parseAttributeValue: false,
|
||||
arrayMode: false,
|
||||
trimValues: true, //Trim string values of tag and attributes
|
||||
cdataTagName: false,
|
||||
cdataPositionChar: '\\c',
|
||||
numParseOptions: {
|
||||
hex: true,
|
||||
leadingZeros: true
|
||||
},
|
||||
tagValueProcessor: function(a, tagName) {
|
||||
return a;
|
||||
},
|
||||
attrValueProcessor: function(a, attrName) {
|
||||
return a;
|
||||
},
|
||||
stopNodes: [],
|
||||
alwaysCreateTextNode: false
|
||||
//decodeStrict: false,
|
||||
};
|
||||
|
||||
exports.defaultOptions = defaultOptions;
|
||||
|
||||
const props = [
|
||||
'attributeNamePrefix',
|
||||
'attrNodeName',
|
||||
'textNodeName',
|
||||
'ignoreAttributes',
|
||||
'ignoreNameSpace',
|
||||
'allowBooleanAttributes',
|
||||
'parseNodeValue',
|
||||
'parseAttributeValue',
|
||||
'arrayMode',
|
||||
'trimValues',
|
||||
'cdataTagName',
|
||||
'cdataPositionChar',
|
||||
'tagValueProcessor',
|
||||
'attrValueProcessor',
|
||||
'parseTrueNumberOnly',
|
||||
'numParseOptions',
|
||||
'stopNodes',
|
||||
'alwaysCreateTextNode'
|
||||
];
|
||||
exports.props = props;
|
||||
|
||||
/**
|
||||
* Trim -> valueProcessor -> parse value
|
||||
* @param {string} tagName
|
||||
* @param {string} val
|
||||
* @param {object} options
|
||||
*/
|
||||
function processTagValue(tagName, val, options) {
|
||||
if (val) {
|
||||
if (options.trimValues) {
|
||||
val = val.trim();
|
||||
}
|
||||
val = options.tagValueProcessor(val, tagName);
|
||||
val = parseValue(val, options.parseNodeValue, options.numParseOptions);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
function resolveNameSpace(tagname, options) {
|
||||
if (options.ignoreNameSpace) {
|
||||
const tags = tagname.split(':');
|
||||
const prefix = tagname.charAt(0) === '/' ? '/' : '';
|
||||
if (tags[0] === 'xmlns') {
|
||||
return '';
|
||||
}
|
||||
if (tags.length === 2) {
|
||||
tagname = prefix + tags[1];
|
||||
}
|
||||
}
|
||||
return tagname;
|
||||
}
|
||||
|
||||
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 '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: change regex to capture NS
|
||||
//const attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])((.|\n)*?)\\2","gm");
|
||||
const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])(.*?)\\3)?', 'g');
|
||||
|
||||
function buildAttributesMap(attrStr, options) {
|
||||
if (!options.ignoreAttributes && 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 = resolveNameSpace(matches[i][1], options);
|
||||
if (attrName.length) {
|
||||
if (matches[i][4] !== undefined) {
|
||||
if (options.trimValues) {
|
||||
matches[i][4] = matches[i][4].trim();
|
||||
}
|
||||
matches[i][4] = options.attrValueProcessor(matches[i][4], attrName);
|
||||
attrs[options.attributeNamePrefix + attrName] = parseValue(
|
||||
matches[i][4],
|
||||
options.parseAttributeValue,
|
||||
options.numParseOptions
|
||||
);
|
||||
} else if (options.allowBooleanAttributes) {
|
||||
attrs[options.attributeNamePrefix + attrName] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Object.keys(attrs).length) {
|
||||
return;
|
||||
}
|
||||
if (options.attrNodeName) {
|
||||
const attrCollection = {};
|
||||
attrCollection[options.attrNodeName] = attrs;
|
||||
return attrCollection;
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
}
|
||||
|
||||
const getTraversalObj = function(xmlData, options) {
|
||||
xmlData = xmlData.replace(/\r\n?/g, "\n");
|
||||
options = buildOptions(options, defaultOptions, props);
|
||||
const xmlObj = new xmlNode('!xml');
|
||||
let currentNode = xmlObj;
|
||||
let textData = "";
|
||||
|
||||
//function match(xmlData){
|
||||
for(let i=0; i< xmlData.length; i++){
|
||||
const ch = xmlData[i];
|
||||
if(ch === '<'){
|
||||
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(options.ignoreNameSpace){
|
||||
const colonIndex = tagName.indexOf(":");
|
||||
if(colonIndex !== -1){
|
||||
tagName = tagName.substr(colonIndex+1);
|
||||
}
|
||||
}
|
||||
|
||||
/* if (currentNode.parent) {
|
||||
currentNode.parent.val = util.getValue(currentNode.parent.val) + '' + processTagValue2(tagName, textData , options);
|
||||
} */
|
||||
if(currentNode){
|
||||
if(currentNode.val){
|
||||
currentNode.val = util.getValue(currentNode.val) + '' + processTagValue(tagName, textData , options);
|
||||
}else{
|
||||
currentNode.val = processTagValue(tagName, textData , options);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.stopNodes.length && options.stopNodes.includes(currentNode.tagname)) {
|
||||
currentNode.child = []
|
||||
if (currentNode.attrsMap == undefined) { currentNode.attrsMap = {}}
|
||||
currentNode.val = xmlData.substr(currentNode.startIndex + 1, i - currentNode.startIndex - 1)
|
||||
}
|
||||
currentNode = currentNode.parent;
|
||||
textData = "";
|
||||
i = closeIndex;
|
||||
} else if( xmlData[i+1] === '?') {
|
||||
i = findClosingIndex(xmlData, "?>", i, "Pi Tag is not closed.")
|
||||
} else if(xmlData.substr(i + 1, 3) === '!--') {
|
||||
i = findClosingIndex(xmlData, "-->", i, "Comment is not closed.")
|
||||
} else if( xmlData.substr(i + 1, 2) === '!D') {
|
||||
const closeIndex = findClosingIndex(xmlData, ">", i, "DOCTYPE is not closed.")
|
||||
const tagExp = xmlData.substring(i, closeIndex);
|
||||
if(tagExp.indexOf("[") >= 0){
|
||||
i = xmlData.indexOf("]>", i) + 1;
|
||||
}else{
|
||||
i = closeIndex;
|
||||
}
|
||||
}else if(xmlData.substr(i + 1, 2) === '![') {
|
||||
const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2
|
||||
const tagExp = xmlData.substring(i + 9,closeIndex);
|
||||
|
||||
//considerations
|
||||
//1. CDATA will always have parent node
|
||||
//2. A tag with CDATA is not a leaf node so it's value would be string type.
|
||||
if(textData){
|
||||
currentNode.val = util.getValue(currentNode.val) + '' + processTagValue(currentNode.tagname, textData , options);
|
||||
textData = "";
|
||||
}
|
||||
|
||||
if (options.cdataTagName) {
|
||||
//add cdata node
|
||||
const childNode = new xmlNode(options.cdataTagName, currentNode, tagExp);
|
||||
currentNode.addChild(childNode);
|
||||
//for backtracking
|
||||
currentNode.val = util.getValue(currentNode.val) + options.cdataPositionChar;
|
||||
//add rest value to parent node
|
||||
if (tagExp) {
|
||||
childNode.val = tagExp;
|
||||
}
|
||||
} else {
|
||||
currentNode.val = (currentNode.val || '') + (tagExp || '');
|
||||
}
|
||||
|
||||
i = closeIndex + 2;
|
||||
}else {//Opening tag
|
||||
const result = closingIndexForOpeningTag(xmlData, i+1)
|
||||
let tagExp = result.data;
|
||||
const closeIndex = result.index;
|
||||
const separatorIndex = tagExp.indexOf(" ");
|
||||
let tagName = tagExp;
|
||||
let shouldBuildAttributesMap = true;
|
||||
if(separatorIndex !== -1){
|
||||
tagName = tagExp.substr(0, separatorIndex).replace(/\s\s*$/, '');
|
||||
tagExp = tagExp.substr(separatorIndex + 1);
|
||||
}
|
||||
|
||||
if(options.ignoreNameSpace){
|
||||
const colonIndex = tagName.indexOf(":");
|
||||
if(colonIndex !== -1){
|
||||
tagName = tagName.substr(colonIndex+1);
|
||||
shouldBuildAttributesMap = tagName !== result.data.substr(colonIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//save text to parent node
|
||||
if (currentNode && textData) {
|
||||
if(currentNode.tagname !== '!xml'){
|
||||
currentNode.val = util.getValue(currentNode.val) + '' + processTagValue( currentNode.tagname, textData, options);
|
||||
}
|
||||
}
|
||||
|
||||
if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){//selfClosing tag
|
||||
|
||||
if(tagName[tagName.length - 1] === "/"){ //remove trailing '/'
|
||||
tagName = tagName.substr(0, tagName.length - 1);
|
||||
tagExp = tagName;
|
||||
}else{
|
||||
tagExp = tagExp.substr(0, tagExp.length - 1);
|
||||
}
|
||||
|
||||
const childNode = new xmlNode(tagName, currentNode, '');
|
||||
if(tagName !== tagExp){
|
||||
childNode.attrsMap = buildAttributesMap(tagExp, options);
|
||||
}
|
||||
currentNode.addChild(childNode);
|
||||
}else{//opening tag
|
||||
|
||||
const childNode = new xmlNode( tagName, currentNode );
|
||||
if (options.stopNodes.length && options.stopNodes.includes(childNode.tagname)) {
|
||||
childNode.startIndex=closeIndex;
|
||||
}
|
||||
if(tagName !== tagExp && shouldBuildAttributesMap){
|
||||
childNode.attrsMap = buildAttributesMap(tagExp, options);
|
||||
}
|
||||
currentNode.addChild(childNode);
|
||||
currentNode = childNode;
|
||||
}
|
||||
textData = "";
|
||||
i = closeIndex;
|
||||
}
|
||||
}else{
|
||||
textData += xmlData[i];
|
||||
}
|
||||
}
|
||||
return xmlObj;
|
||||
}
|
||||
|
||||
function closingIndexForOpeningTag(data, i){
|
||||
let attrBoundary;
|
||||
let tagExp = "";
|
||||
for (let index = i; index < data.length; index++) {
|
||||
let ch = data[index];
|
||||
if (attrBoundary) {
|
||||
if (ch === attrBoundary) attrBoundary = "";//reset
|
||||
} else if (ch === '"' || ch === "'") {
|
||||
attrBoundary = ch;
|
||||
} else if (ch === '>') {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
exports.getTraversalObj = getTraversalObj;
|
||||
Reference in New Issue
Block a user