From 5d4d84656256b7081168f8554d5417f3d25a41e9 Mon Sep 17 00:00:00 2001 From: amit kumar gupta Date: Sun, 9 Apr 2023 05:49:16 +0530 Subject: [PATCH] support updateAttributes --- spec/attr_spec.js | 100 ++++++++++++++++++++++++++++++ src/fxp.d.ts | 1 + src/xmlparser/OptionsBuilder.js | 3 + src/xmlparser/OrderedObjParser.js | 14 ++--- 4 files changed, 111 insertions(+), 7 deletions(-) diff --git a/spec/attr_spec.js b/spec/attr_spec.js index 5840afd3..0d8b1e9a 100644 --- a/spec/attr_spec.js +++ b/spec/attr_spec.js @@ -359,4 +359,104 @@ id="7" data="foo bar" bug="true"/>`; // console.log(output); expect(output.replace(/\s+/g, "")).toEqual(XMLdata.replace(/\s+/g, "")); }); + it("should parse attributes with valid names", function() { + const xmlData = ` + + + + + + `; + const expected = { + "root": { + "a": [ + { + "keep": "me" + }, + "", + { + "need": "friend", + "friend": "me" + }, + { + "Camel": "case", + "makeme": "lower" + } + ], + "b": { + "change": "VAL" + } + } + }; + const options = { + attributeNamePrefix: "", + ignoreAttributes: false, + parseAttributeValue: true, + updateAttributes(tagName, attrs, jPath){ + if(attrs["skip"]) delete attrs["skip"] + if(attrs["camel"]) { + attrs["Camel"] = attrs["camel"]; + delete attrs["camel"]; + } + if(attrs["need"]) { + attrs["friend"] = "me"; + } + if(attrs["MakeMe"]) { + attrs["makeme"] = attrs["MakeMe"]; + delete attrs["MakeMe"]; + } + if(attrs["change"]) { + attrs["change"] = attrs["change"].toUpperCase(); + } + return attrs; + } + }; + + const parser = new XMLParser(options); + let result = parser.parse(xmlData); + + // console.log(JSON.stringify(result,null,4)); + expect(result).toEqual(expected); + + result = XMLValidator.validate(xmlData); + expect(result).toBe(true); + }); + it("should parse attributes with valid names", function() { + const xmlData = ` + + + + + + `; + const expected = { + "root": { + "a": [ + "", + "", + "", + "" + ], + "b": "" + } + }; + const options = { + attributeNamePrefix: "", + ignoreAttributes: false, + parseAttributeValue: true, + updateAttributes(tagName, attrs,jPath){ + // console.log("called") + return null; + } + }; + + const parser = new XMLParser(options); + let result = parser.parse(xmlData); + + // console.log(JSON.stringify(result,null,4)); + expect(result).toEqual(expected); + + result = XMLValidator.validate(xmlData); + expect(result).toBe(true); + }); }); diff --git a/src/fxp.d.ts b/src/fxp.d.ts index 45d39c8f..881d146e 100644 --- a/src/fxp.d.ts +++ b/src/fxp.d.ts @@ -32,6 +32,7 @@ Control how tag value should be parsed. Called only if tag value is not empty ignorePiTags: boolean; transformTagName: ((tagName: string) => string) | false; transformAttributeName: ((attributeName: string) => string) | false; + updateAttributes(tagName: string, jPath: string, attrs: {[k: string]: string}): {[k: string]: string}; }; type strnumOptions = { hex: boolean; diff --git a/src/xmlparser/OptionsBuilder.js b/src/xmlparser/OptionsBuilder.js index 681a06df..5bf6b29d 100644 --- a/src/xmlparser/OptionsBuilder.js +++ b/src/xmlparser/OptionsBuilder.js @@ -34,6 +34,9 @@ const defaultOptions = { ignorePiTags: false, transformTagName: false, transformAttributeName: false, + updateAttributes: function(tagName, attrs, jPath){ + return attrs; + } }; const buildOptions = function(options) { diff --git a/src/xmlparser/OrderedObjParser.js b/src/xmlparser/OrderedObjParser.js index b4c9f6c0..6b3ab6d3 100644 --- a/src/xmlparser/OrderedObjParser.js +++ b/src/xmlparser/OrderedObjParser.js @@ -121,7 +121,7 @@ function resolveNameSpace(tagname) { //const attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])((.|\n)*?)\\2","gm"); const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm'); -function buildAttributesMap(attrStr, jPath) { +function buildAttributesMap(attrStr, jPath, tagName) { if (!this.options.ignoreAttributes && typeof attrStr === 'string') { // attrStr = attrStr.replace(/\r?\n/g, ' '); //attrStr = attrStr || attrStr.trim(); @@ -171,7 +171,7 @@ function buildAttributesMap(attrStr, jPath) { attrCollection[this.options.attributesGroupName] = attrs; return attrCollection; } - return attrs; + return this.options.updateAttributes(tagName, attrs, jPath) } } @@ -207,7 +207,7 @@ const parseXml = function(xmlData) { jPath = jPath.substr(0, jPath.lastIndexOf(".")); - currentNode = this.tagsNodeStack.pop();//avoid recurssion, set the parent tag scope + currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope textData = ""; i = closeIndex; } else if( xmlData[i+1] === '?') { @@ -224,7 +224,7 @@ const parseXml = function(xmlData) { childNode.add(this.options.textNodeName, ""); if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){ - childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath); + childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath, tagData.tagName); } currentNode.addChild(childNode); @@ -314,7 +314,7 @@ const parseXml = function(xmlData) { const childNode = new xmlNode(tagName); if(tagName !== tagExp && attrExpPresent){ - childNode[":@"] = this.buildAttributesMap(tagExp, jPath); + childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName); } if(tagContent) { tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true); @@ -340,7 +340,7 @@ const parseXml = function(xmlData) { const childNode = new xmlNode(tagName); if(tagName !== tagExp && attrExpPresent){ - childNode[":@"] = this.buildAttributesMap(tagExp, jPath); + childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName); } jPath = jPath.substr(0, jPath.lastIndexOf(".")); currentNode.addChild(childNode); @@ -351,7 +351,7 @@ const parseXml = function(xmlData) { this.tagsNodeStack.push(currentNode); if(tagName !== tagExp && attrExpPresent){ - childNode[":@"] = this.buildAttributesMap(tagExp, jPath); + childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName); } currentNode.addChild(childNode); currentNode = childNode;