fast-xml-parser 4.4.1 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/package.json +1 -2
- package/src/fxp.d.ts +19 -3
- package/src/ignoreAttributes.js +20 -0
- package/src/xmlbuilder/json2xml.js +13 -10
- package/src/xmlparser/OrderedObjParser.js +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<small>Note: If you find missing information about particular minor version, that version must have been changed without any functional change in this library.</small>
|
|
2
2
|
|
|
3
|
+
**4.5.0 / 2024-09-03**
|
|
4
|
+
- feat #666: ignoreAttributes support function, and array of string or regex (By [ArtemM](https://github.com/mav-rik))
|
|
5
|
+
|
|
3
6
|
**4.4.1 / 2024-07-28**
|
|
4
7
|
- v5 fix: maximum length limit to currency value
|
|
5
8
|
- fix #634: build attributes with oneListGroup and attributesGroupName (#653)(By [Andreas Naziris](https://github.com/a-rasin))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-xml-parser",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Validate XML, Parse XML, Build XML without C/C++ based libraries",
|
|
5
5
|
"main": "./src/fxp.js",
|
|
6
6
|
"scripts": {
|
|
@@ -49,7 +49,6 @@
|
|
|
49
49
|
"@babel/register": "^7.13.8",
|
|
50
50
|
"@types/node": "20",
|
|
51
51
|
"babel-loader": "^8.2.2",
|
|
52
|
-
"cytorus": "^0.2.9",
|
|
53
52
|
"eslint": "^8.3.0",
|
|
54
53
|
"he": "^1.2.0",
|
|
55
54
|
"jasmine": "^3.6.4",
|
package/src/fxp.d.ts
CHANGED
|
@@ -30,9 +30,17 @@ type X2jOptions = {
|
|
|
30
30
|
/**
|
|
31
31
|
* Whether to ignore attributes when parsing
|
|
32
32
|
*
|
|
33
|
+
* When `true` - ignores all the attributes
|
|
34
|
+
*
|
|
35
|
+
* When `false` - parses all the attributes
|
|
36
|
+
*
|
|
37
|
+
* When `Array<string | RegExp>` - filters out attributes that match provided patterns
|
|
38
|
+
*
|
|
39
|
+
* When `Function` - calls the function for each attribute and filters out those for which the function returned `true`
|
|
40
|
+
*
|
|
33
41
|
* Defaults to `true`
|
|
34
42
|
*/
|
|
35
|
-
ignoreAttributes?: boolean;
|
|
43
|
+
ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPath: string) => boolean);
|
|
36
44
|
|
|
37
45
|
/**
|
|
38
46
|
* Whether to remove namespace string from tag and attribute names
|
|
@@ -250,11 +258,19 @@ type XmlBuilderOptions = {
|
|
|
250
258
|
textNodeName?: string;
|
|
251
259
|
|
|
252
260
|
/**
|
|
253
|
-
* Whether to ignore attributes when
|
|
261
|
+
* Whether to ignore attributes when building
|
|
262
|
+
*
|
|
263
|
+
* When `true` - ignores all the attributes
|
|
264
|
+
*
|
|
265
|
+
* When `false` - builds all the attributes
|
|
266
|
+
*
|
|
267
|
+
* When `Array<string | RegExp>` - filters out attributes that match provided patterns
|
|
268
|
+
*
|
|
269
|
+
* When `Function` - calls the function for each attribute and filters out those for which the function returned `true`
|
|
254
270
|
*
|
|
255
271
|
* Defaults to `true`
|
|
256
272
|
*/
|
|
257
|
-
ignoreAttributes?: boolean;
|
|
273
|
+
ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPath: string) => boolean);
|
|
258
274
|
|
|
259
275
|
/**
|
|
260
276
|
* Give a property name to set CDATA values to instead of merging to tag's text value
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function getIgnoreAttributesFn(ignoreAttributes) {
|
|
2
|
+
if (typeof ignoreAttributes === 'function') {
|
|
3
|
+
return ignoreAttributes
|
|
4
|
+
}
|
|
5
|
+
if (Array.isArray(ignoreAttributes)) {
|
|
6
|
+
return (attrName) => {
|
|
7
|
+
for (const pattern of ignoreAttributes) {
|
|
8
|
+
if (typeof pattern === 'string' && attrName === pattern) {
|
|
9
|
+
return true
|
|
10
|
+
}
|
|
11
|
+
if (pattern instanceof RegExp && pattern.test(attrName)) {
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return () => false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = getIgnoreAttributesFn
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
//parse Empty Node as self closing node
|
|
3
3
|
const buildFromOrderedJs = require('./orderedJs2Xml');
|
|
4
|
+
const getIgnoreAttributesFn = require('../ignoreAttributes')
|
|
4
5
|
|
|
5
6
|
const defaultOptions = {
|
|
6
7
|
attributeNamePrefix: '@_',
|
|
@@ -38,11 +39,12 @@ const defaultOptions = {
|
|
|
38
39
|
|
|
39
40
|
function Builder(options) {
|
|
40
41
|
this.options = Object.assign({}, defaultOptions, options);
|
|
41
|
-
if (this.options.ignoreAttributes || this.options.attributesGroupName) {
|
|
42
|
+
if (this.options.ignoreAttributes === true || this.options.attributesGroupName) {
|
|
42
43
|
this.isAttribute = function(/*a*/) {
|
|
43
44
|
return false;
|
|
44
45
|
};
|
|
45
46
|
} else {
|
|
47
|
+
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes)
|
|
46
48
|
this.attrPrefixLen = this.options.attributeNamePrefix.length;
|
|
47
49
|
this.isAttribute = isAttribute;
|
|
48
50
|
}
|
|
@@ -71,13 +73,14 @@ Builder.prototype.build = function(jObj) {
|
|
|
71
73
|
[this.options.arrayNodeName] : jObj
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
|
-
return this.j2x(jObj, 0).val;
|
|
76
|
+
return this.j2x(jObj, 0, []).val;
|
|
75
77
|
}
|
|
76
78
|
};
|
|
77
79
|
|
|
78
|
-
Builder.prototype.j2x = function(jObj, level) {
|
|
80
|
+
Builder.prototype.j2x = function(jObj, level, ajPath) {
|
|
79
81
|
let attrStr = '';
|
|
80
82
|
let val = '';
|
|
83
|
+
const jPath = ajPath.join('.')
|
|
81
84
|
for (let key in jObj) {
|
|
82
85
|
if(!Object.prototype.hasOwnProperty.call(jObj, key)) continue;
|
|
83
86
|
if (typeof jObj[key] === 'undefined') {
|
|
@@ -100,9 +103,9 @@ Builder.prototype.j2x = function(jObj, level) {
|
|
|
100
103
|
} else if (typeof jObj[key] !== 'object') {
|
|
101
104
|
//premitive type
|
|
102
105
|
const attr = this.isAttribute(key);
|
|
103
|
-
if (attr) {
|
|
106
|
+
if (attr && !this.ignoreAttributesFn(attr, jPath)) {
|
|
104
107
|
attrStr += this.buildAttrPairStr(attr, '' + jObj[key]);
|
|
105
|
-
}else {
|
|
108
|
+
} else if (!attr) {
|
|
106
109
|
//tag value
|
|
107
110
|
if (key === this.options.textNodeName) {
|
|
108
111
|
let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
|
|
@@ -126,13 +129,13 @@ Builder.prototype.j2x = function(jObj, level) {
|
|
|
126
129
|
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
|
127
130
|
} else if (typeof item === 'object') {
|
|
128
131
|
if(this.options.oneListGroup){
|
|
129
|
-
const result = this.j2x(item, level + 1);
|
|
132
|
+
const result = this.j2x(item, level + 1, ajPath.concat(key));
|
|
130
133
|
listTagVal += result.val;
|
|
131
134
|
if (this.options.attributesGroupName && item.hasOwnProperty(this.options.attributesGroupName)) {
|
|
132
135
|
listTagAttr += result.attrStr
|
|
133
136
|
}
|
|
134
137
|
}else{
|
|
135
|
-
listTagVal += this.processTextOrObjNode(item, key, level)
|
|
138
|
+
listTagVal += this.processTextOrObjNode(item, key, level, ajPath)
|
|
136
139
|
}
|
|
137
140
|
} else {
|
|
138
141
|
if (this.options.oneListGroup) {
|
|
@@ -157,7 +160,7 @@ Builder.prototype.j2x = function(jObj, level) {
|
|
|
157
160
|
attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]]);
|
|
158
161
|
}
|
|
159
162
|
} else {
|
|
160
|
-
val += this.processTextOrObjNode(jObj[key], key, level)
|
|
163
|
+
val += this.processTextOrObjNode(jObj[key], key, level, ajPath)
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
}
|
|
@@ -172,8 +175,8 @@ Builder.prototype.buildAttrPairStr = function(attrName, val){
|
|
|
172
175
|
} else return ' ' + attrName + '="' + val + '"';
|
|
173
176
|
}
|
|
174
177
|
|
|
175
|
-
function processTextOrObjNode (object, key, level) {
|
|
176
|
-
const result = this.j2x(object, level + 1);
|
|
178
|
+
function processTextOrObjNode (object, key, level, ajPath) {
|
|
179
|
+
const result = this.j2x(object, level + 1, ajPath.concat(key));
|
|
177
180
|
if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
|
|
178
181
|
return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level);
|
|
179
182
|
} else {
|
|
@@ -5,6 +5,7 @@ const util = require('../util');
|
|
|
5
5
|
const xmlNode = require('./xmlNode');
|
|
6
6
|
const readDocType = require("./DocTypeReader");
|
|
7
7
|
const toNumber = require("strnum");
|
|
8
|
+
const getIgnoreAttributesFn = require('../ignoreAttributes')
|
|
8
9
|
|
|
9
10
|
// const regx =
|
|
10
11
|
// '<((!\\[CDATA\\[([\\s\\S]*?)(]]>))|((NAME:)?(NAME))([^>]*)>|((\\/)(NAME)\\s*>))([^<]*)'
|
|
@@ -53,6 +54,7 @@ class OrderedObjParser{
|
|
|
53
54
|
this.readStopNodeData = readStopNodeData;
|
|
54
55
|
this.saveTextToParentTag = saveTextToParentTag;
|
|
55
56
|
this.addChild = addChild;
|
|
57
|
+
this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes)
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
}
|
|
@@ -125,7 +127,7 @@ function resolveNameSpace(tagname) {
|
|
|
125
127
|
const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm');
|
|
126
128
|
|
|
127
129
|
function buildAttributesMap(attrStr, jPath, tagName) {
|
|
128
|
-
if (
|
|
130
|
+
if (this.options.ignoreAttributes !== true && typeof attrStr === 'string') {
|
|
129
131
|
// attrStr = attrStr.replace(/\r?\n/g, ' ');
|
|
130
132
|
//attrStr = attrStr || attrStr.trim();
|
|
131
133
|
|
|
@@ -134,6 +136,9 @@ function buildAttributesMap(attrStr, jPath, tagName) {
|
|
|
134
136
|
const attrs = {};
|
|
135
137
|
for (let i = 0; i < len; i++) {
|
|
136
138
|
const attrName = this.resolveNameSpace(matches[i][1]);
|
|
139
|
+
if (this.ignoreAttributesFn(attrName, jPath)) {
|
|
140
|
+
continue
|
|
141
|
+
}
|
|
137
142
|
let oldVal = matches[i][4];
|
|
138
143
|
let aName = this.options.attributeNamePrefix + attrName;
|
|
139
144
|
if (attrName.length) {
|