Skip to content

Commit

Permalink
support updateTag
Browse files Browse the repository at this point in the history
  • Loading branch information
amitguptagwl committed Apr 9, 2023
1 parent 5d4d846 commit 652a29e
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 109 deletions.
101 changes: 1 addition & 100 deletions spec/attr_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,104 +359,5 @@ 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 = `<root>
<a keep="me" skip="me"></a>
<a skip="me"></a>
<a need="friend"></a>
<a camel="case" MakeMe="lower"></a>
<b change="val"></b>
</root>`;
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 = `<root>
<a keep="me" skip="me"></a>
<a skip="me"></a>
<a need="friend"></a>
<a camel="case" MakeMe="lower"></a>
<b change="val"></b>
</root>`;
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);
});
});

182 changes: 182 additions & 0 deletions spec/updateTag_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
"use strict";

const {XMLParser, XMLBuilder, XMLValidator} = require("../src/fxp");
const he = require("he");

describe("XMLParser updateTag ", function() {
it("should delete, join, update attribute name and value", function() {
const xmlData = `<root>
<a keep="me" skip="me"></a>
<a skip="me"></a>
<a need="friend"></a>
<a camel="case" MakeMe="lower"></a>
<b change="val"></b>
</root>`;
const expected = {
"root": {
"a": [
{
"keep": "me"
},
"",
{
"need": "friend",
"friend": "me"
},
{
"Camel": "case",
"makeme": "lower"
}
],
"b": {
"change": "VAL"
}
}
};
const options = {
attributeNamePrefix: "",
ignoreAttributes: false,
parseAttributeValue: true,
updateTag(tagName, jPath, attrs){
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 tagName;
}
};

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 delete all the attributes", function() {
const xmlData = `<root>
<a keep="me" skip="me"></a>
<a skip="me"></a>
<a need="friend"></a>
<a camel="case" MakeMe="lower"></a>
<b change="val"></b>
</root>`;
const expected = {
"root": {
"a": [
"",
"",
"",
""
],
"b": ""
}
};
const options = {
attributeNamePrefix: "",
ignoreAttributes: false,
parseAttributeValue: true,
updateTag(tagName, jPath, attrs){
for (var k in attrs){
if (attrs.hasOwnProperty(k)){
delete attrs[k];
}
}
return tagName;
}
};

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 skip a tag or modify tag name", function() {
const xmlData = `<html>
<header></header>
<body>
<h1 class="highlight" >Post title</h1>
<content>
<img width="200" height="500">
<p>some text</p>
<img width="200" height="200">
<p join="a" all="b" in="c" one="d" >some text 2</p>
<img width="500" height="500">
</content>
<script></script>
</body>
</html>`;
const expected = {
"html": {
"header": "",
"body": {
"h1": {
"#text": "Post title",
"class": "highlight underline"
},
"div": {
"p": [
"some text",
{
"#text": "some text 2",
"joint": "abcd"
}
],
"img": {
"width": "200",
"height": "200"
}
}
}
}
};
const options = {
ignoreAttributes: false,
attributeNamePrefix: "",
updateTag: function(tagname, jPath, attrs){

if(tagname ==="h1" && attrs["class"] && attrs["class"].indexOf("highlight") > -1){
attrs["class"] += " underline"
}else if(attrs["join"]){
let val = "";
Object.keys(attrs).forEach( a => {
val+= attrs[a]
delete attrs[a];
});
attrs["joint"] = val;
}
if(tagname === "script") return false;
else if(tagname === "img"){
if(attrs.width > 200 || attrs.height > 200) return false;
}else if(tagname === "content"){
return "div"
}
return tagname;
},
unpairedTags: ["img"]
};
const parser = new XMLParser(options);
let result = parser.parse(xmlData);

// console.log(JSON.stringify(result,null,4));
expect(result).toEqual(expected);

});
});
9 changes: 8 additions & 1 deletion src/fxp.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ 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};
/**
Change the tag name when a different name is returned. Skip the tag from parsed result when false is returned.
Modify `attrs` object to control attributes for the given tag.
@returns {string} new tag name.
@returns false to skip the tag
*/
updateTag: (tagName: string, jPath: string, attrs: {[k: string]: string}) => string | boolean;
};
type strnumOptions = {
hex: boolean;
Expand Down
4 changes: 2 additions & 2 deletions src/xmlparser/OptionsBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ const defaultOptions = {
ignorePiTags: false,
transformTagName: false,
transformAttributeName: false,
updateAttributes: function(tagName, attrs, jPath){
return attrs;
updateTag: function(tagName, jPath, attrs){
return tagName
}
};

Expand Down
24 changes: 18 additions & 6 deletions src/xmlparser/OrderedObjParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class OrderedObjParser{
this.replaceEntitiesValue = replaceEntitiesValue;
this.readStopNodeData = readStopNodeData;
this.saveTextToParentTag = saveTextToParentTag;
this.addChild = addChild;
}

}
Expand Down Expand Up @@ -171,7 +172,7 @@ function buildAttributesMap(attrStr, jPath, tagName) {
attrCollection[this.options.attributesGroupName] = attrs;
return attrCollection;
}
return this.options.updateAttributes(tagName, attrs, jPath)
return attrs
}
}

Expand Down Expand Up @@ -226,7 +227,7 @@ const parseXml = function(xmlData) {
if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath, tagData.tagName);
}
currentNode.addChild(childNode);
this.addChild(currentNode, childNode, jPath)

}

Expand Down Expand Up @@ -323,7 +324,7 @@ const parseXml = function(xmlData) {
jPath = jPath.substr(0, jPath.lastIndexOf("."));
childNode.add(this.options.textNodeName, tagContent);

currentNode.addChild(childNode);
this.addChild(currentNode, childNode, jPath)
}else{
//selfClosing tag
if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
Expand All @@ -343,7 +344,7 @@ const parseXml = function(xmlData) {
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
}
jPath = jPath.substr(0, jPath.lastIndexOf("."));
currentNode.addChild(childNode);
this.addChild(currentNode, childNode, jPath)
}
//opening tag
else{
Expand All @@ -353,7 +354,7 @@ const parseXml = function(xmlData) {
if(tagName !== tagExp && attrExpPresent){
childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
}
currentNode.addChild(childNode);
this.addChild(currentNode, childNode, jPath)
currentNode = childNode;
}
textData = "";
Expand All @@ -367,6 +368,17 @@ const parseXml = function(xmlData) {
return xmlObj.child;
}

function addChild(currentNode, childNode, jPath){
const result = this.options.updateTag(childNode.tagname, jPath, childNode[":@"])
if(result === false){
}else if(typeof result === "string"){
childNode.tagname = result
currentNode.addChild(childNode);
}else{
currentNode.addChild(childNode);
}
}

const replaceEntitiesValue = function(val){

if(this.options.processEntities){
Expand Down Expand Up @@ -423,7 +435,7 @@ function isItStopNode(stopNodes, jPath, currentTagName){
}

/**
* Returns the tag Expression and where it is ending handling single-dobule quotes situation
* Returns the tag Expression and where it is ending handling single-double quotes situation
* @param {string} xmlData
* @param {number} i starting index
* @returns
Expand Down

0 comments on commit 652a29e

Please sign in to comment.