From fb229246cce5360f02641e4a65839f3d41bbb041 Mon Sep 17 00:00:00 2001 From: "plamen.dimitrov" Date: Wed, 2 Sep 2020 15:25:57 +0300 Subject: [PATCH 1/3] feat:Adding custom parser for the needs of the DFA projects. --- packages/xml2json/index.js | 30 +---- packages/xml2json/package.json | 3 +- packages/xml2json/xmlParser.js | 196 +++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 26 deletions(-) create mode 100644 packages/xml2json/xmlParser.js diff --git a/packages/xml2json/index.js b/packages/xml2json/index.js index 74f70e9..40b68eb 100644 --- a/packages/xml2json/index.js +++ b/packages/xml2json/index.js @@ -1,28 +1,8 @@ -const flatten = require('ut-function.flatten'); -const template = require('ut-function.template'); -const set = require('lodash.set'); -const get = require('lodash.get'); -const xml2js = require('xml2js'); -const xmlParser = new xml2js.Parser({ - charkey: 'text', - mergeAttrs: true, - explicitArray: false, - tagNameProcessors: [xml2js.processors.stripPrefix] -}); +const xmlParser = require('./xmlParser').parse; module.exports = (xmlTemplate, maxDepth = 50) => { - const fn = (async() => template( - JSON.stringify( - Object - .entries(flatten(await xmlParser.parseStringPromise(xmlTemplate), maxDepth)) - .reduce((prev, [name, value]) => { - const path = value.match(/^\${(.*)}$/); - if (path) set(prev, path[1], '$' + `{ut.get(xml, '${name}')}`); - return prev; - }, {}) - ), ['xml'], {get}))(); - return async(xml, json) => { - const result = (await fn)(typeof xml === 'string' ? await xmlParser.parseStringPromise(xml) : await xml); - return json ? result : JSON.parse(result); + return async(xml, xmlTemplatePath) => { + const result = await xmlParser(xmlTemplatePath, xml); + return typeof result === 'object' ? result : JSON.parse(result); }; -}; +}; \ No newline at end of file diff --git a/packages/xml2json/package.json b/packages/xml2json/package.json index 24f03a5..4582c7f 100644 --- a/packages/xml2json/package.json +++ b/packages/xml2json/package.json @@ -7,7 +7,8 @@ "lodash.set": "4.3.2", "ut-function.flatten": "^1.2.1", "ut-function.template": "^1.6.3", - "xml2js": "0.4.22" + "xml2js": "0.4.22", + "xmldom": "^0.3.0" }, "devDependencies": { "sort-keys": "2.0.0", diff --git a/packages/xml2json/xmlParser.js b/packages/xml2json/xmlParser.js new file mode 100644 index 0000000..c7939df --- /dev/null +++ b/packages/xml2json/xmlParser.js @@ -0,0 +1,196 @@ +var xml2js = require('xml2js'); +var fs = require('fs'); +//var util = require('util'); +var DOMParser = require('xmldom').DOMParser; + +//var dataFile = fs.readFileSync('./listCustomer_resp.xml').toString(); + +function getPath(ob, p, attributes) { + if (ob.parentNode) { + p.push(ob.localName); + getPath(ob.parentNode, p, attributes); + var possibleNamesStr = ob.getAttribute('possibleNames'); + if (possibleNamesStr != '') { + attributes.possNames[ob.localName] = possibleNamesStr.split(','); + } + var explArrAttr = ob.getAttribute('explicitArray'); + if (explArrAttr != '' && explArrAttr == 'true') { + attributes.explicitArray = true; + } + } +} + +function removeNilValues(ob) { + if (typeof (ob) == 'object') { + var obKeys = Object.keys(ob); + for (var k in obKeys) { + if (typeof(obKeys[k]) == 'string' && ob[obKeys[k]]['i:nil'] && ob[obKeys[k]]['i:nil'] == 'true') { + return ''; + } + } + } + return ob; +} + +function getMaping(ob, fieldMapings) { + + if (ob.childNodes) { + var keys = Object.keys(ob.childNodes); + keys.forEach(function(pName, i) { + if (pName != 'length') { + var ob1 = ob.childNodes[pName]; + if (ob1.nodeName == 'include') { + var tmplPath = ob1.getAttribute('templatePath'); + if (tmplPath) { + var templString = fs.readFileSync(require.resolve(tmplPath)).toString(); + var templDoc = new DOMParser().parseFromString(templString); + ob.replaceChild(templDoc.firstChild, ob1) + ob1 = ob.childNodes[i]; + } + } + getMaping(ob1, fieldMapings); + } + }); + } else { + var nodeValue = ob.nodeValue; + var pat = /^\$\{(.*)}$/; + var res = nodeValue.match(pat); + if (res && res[1]) { + var path = []; + var attributes = {possNames: {}, explicitArray: false}; + var possNames = {}; + var explicitArray = false; + getPath(ob.parentNode, path, attributes); + path.reverse(); + fieldMapings.push({path: path, fldName: res[1], possblNames: attributes.possNames, explicitArray: attributes.explicitArray}); + + } + } +} + +function extractValue(obbVal, path, pNames, resultObj, possNames, explicitArray) { + var lstName = pNames[(pNames.length - 1)]; + + for (var i = 1; i <= path.length; i++) { + if (obbVal && !Array.isArray(obbVal) && explicitArray && i == (path.length - 1)) { + obbVal = [obbVal]; + } + if (Array.isArray(obbVal)) { + + var childName = path.length == i ? lstName : (pNames.length == 1 ? 'data' : pNames[0]); + resultObj[childName] = resultObj[childName] || []; + + if ((path.length - 1) == i || path.length == i) { + obbVal.forEach(function(ar, ix) { + //var val = ar[path[i]] ? ar[path[i]] : ar; + if (typeof(ar[path[i]]) != 'undefined' || (typeof(path[i]) == 'undefined' && typeof(ar) == 'string')) { + // we enter here when there is such property in result object OR when result object i actualy array of string values + var val = removeNilValues(typeof(path[i]) != 'undefined' ? ar[path[i]] : ar); + if (path.length == i) { + resultObj[childName].push(val); + }else { + if (resultObj[childName][ix]) { + resultObj[childName][ix][lstName] = val; + } else { + var vl = {}; + vl[lstName] = val; + resultObj[childName].push(vl); + } + } + } + }); + } else { + // todo: ...extract array sub objects + //var chOb = extractValue(ar[path[i]], path, pName); + //res.push(chOb); + } + + return resultObj; + } else if (typeof(obbVal) == 'object') { + var foundPn = false; + if (possNames[path[i]]) { + var posNames = possNames[path[i]]; + for (var p in posNames) { + if (typeof(posNames[p]) == 'string') { + if (posNames[p] == '*') { + obbVal = obbVal[Object.keys(obbVal)[0]]; + foundPn = true; + break; + } + if (obbVal[posNames[p]]) { + obbVal = obbVal[posNames[p]]; + foundPn = true; + break; + } + } + } + } + if (!foundPn) { + if (i == path.length) { + resultObj[lstName] = obbVal[path[i]]; + }else { + obbVal = obbVal[path[i]]; + } + } + } else { + //text + if (pNames.length == 1) { + resultObj[lstName] = obbVal; + } else { + if (!obbVal && explicitArray) { + resultObj[pNames[0]] = resultObj[pNames[0]] || []; + }else { + resultObj[pNames[0]] = resultObj[pNames[0]] || {}; + resultObj[pNames[0]][lstName] = obbVal; + } + } + } + + } + +} + +function tagNameProcessor(name) { + + var r = name.split(':'); + return r[r.length - 1]; +} + +////////////////////////////////////////////////////// + +module.exports = { + + parse: function(templName, data){ + + var templFile = fs.readFileSync(require.resolve(templName)).toString(); + var doc = new DOMParser().parseFromString(templFile); + var fieldMapings = []; + getMaping(doc, fieldMapings); + + return new Promise(function(resolve, reject) { + xml2js.parseString(data, {trim: true, + ignoreAttrs: false, + explicitArray: false, + tagNameProcessors: [tagNameProcessor] + }, + function(err, reslt) { + if(err){ + reject(err); + return; + } + var prsRes = {}; + for (var k in fieldMapings) { + if(typeof(fieldMapings[k]) == 'object') { + var path = fieldMapings[k].path; + var propNames = fieldMapings[k].fldName.split('.'); + var obbVal = reslt[path[0]]; + extractValue(obbVal, path, propNames, prsRes, fieldMapings[k].possblNames, fieldMapings[k].explicitArray); + } + } + //console.log(reslt); + resolve(prsRes); + } + ); + }); + } +} \ No newline at end of file From ca4c4bea2809cebe912e78d66b42d74c0f685622 Mon Sep 17 00:00:00 2001 From: "plamen.dimitrov" Date: Thu, 3 Sep 2020 12:30:08 +0300 Subject: [PATCH 2/3] fix:Adopt tests to new functionality. --- packages/xml2json/index.js | 2 +- packages/xml2json/index.test.js | 18 +--- packages/xml2json/xmlParser.js | 172 +++++++++++++++----------------- 3 files changed, 84 insertions(+), 108 deletions(-) diff --git a/packages/xml2json/index.js b/packages/xml2json/index.js index 40b68eb..b6f3aa2 100644 --- a/packages/xml2json/index.js +++ b/packages/xml2json/index.js @@ -5,4 +5,4 @@ module.exports = (xmlTemplate, maxDepth = 50) => { const result = await xmlParser(xmlTemplatePath, xml); return typeof result === 'object' ? result : JSON.parse(result); }; -}; \ No newline at end of file +}; diff --git a/packages/xml2json/index.test.js b/packages/xml2json/index.test.js index fcede9d..e0c7525 100644 --- a/packages/xml2json/index.test.js +++ b/packages/xml2json/index.test.js @@ -1,22 +1,12 @@ -const sortKeys = require('sort-keys'); const path = require('path'); const tap = require('tap'); const fs = require('fs'); const parse = require('./')(fs.readFileSync(path.resolve(__dirname, 'test', 'template.xml')).toString()); +const templatePath = (path.resolve(__dirname, 'test', 'template.xml').toString()); const payload = fs.readFileSync(path.resolve(__dirname, 'test', 'payload.xml')).toString(); tap.test('parse', async assert => { - assert.matchSnapshot(sortKeys(await parse(payload)), 'parse xml string to object'); - assert.matchSnapshot(await parse(payload, true), 'parse xml string to JSON'); - assert.matchSnapshot(sortKeys(await parse({ - some: { - deep: { - nested: { - structure: 'value 1' - } - }, - veryVeryLongTagName: 'value 2' - } - })), 'extract object from parsed xml'); - assert.end(); + const wantedResult = { 'a': 'value 1', 'b': { 'c': 'value 2' }, 'd': undefined }; + assert.deepEqual(await parse(payload, templatePath), wantedResult, 'parse xml string to JSON'); + // assert.end(); }); diff --git a/packages/xml2json/xmlParser.js b/packages/xml2json/xmlParser.js index c7939df..c91ef78 100644 --- a/packages/xml2json/xmlParser.js +++ b/packages/xml2json/xmlParser.js @@ -1,30 +1,27 @@ -var xml2js = require('xml2js'); -var fs = require('fs'); -//var util = require('util'); -var DOMParser = require('xmldom').DOMParser; - -//var dataFile = fs.readFileSync('./listCustomer_resp.xml').toString(); +const xml2js = require('xml2js'); +const fs = require('fs'); +const DOMParser = require('xmldom').DOMParser; function getPath(ob, p, attributes) { if (ob.parentNode) { p.push(ob.localName); getPath(ob.parentNode, p, attributes); - var possibleNamesStr = ob.getAttribute('possibleNames'); - if (possibleNamesStr != '') { + const possibleNamesStr = ob.getAttribute('possibleNames'); + if (possibleNamesStr !== '') { attributes.possNames[ob.localName] = possibleNamesStr.split(','); } - var explArrAttr = ob.getAttribute('explicitArray'); - if (explArrAttr != '' && explArrAttr == 'true') { + const explArrAttr = ob.getAttribute('explicitArray'); + if (explArrAttr !== '' && explArrAttr === 'true') { attributes.explicitArray = true; } } } function removeNilValues(ob) { - if (typeof (ob) == 'object') { - var obKeys = Object.keys(ob); - for (var k in obKeys) { - if (typeof(obKeys[k]) == 'string' && ob[obKeys[k]]['i:nil'] && ob[obKeys[k]]['i:nil'] == 'true') { + if (typeof (ob) === 'object') { + const obKeys = Object.keys(ob); + for (const k in obKeys) { + if (typeof (obKeys[k]) === 'string' && ob[obKeys[k]]['i:nil'] && ob[obKeys[k]]['i:nil'] === 'true') { return ''; } } @@ -33,18 +30,17 @@ function removeNilValues(ob) { } function getMaping(ob, fieldMapings) { - if (ob.childNodes) { - var keys = Object.keys(ob.childNodes); + const keys = Object.keys(ob.childNodes); keys.forEach(function(pName, i) { - if (pName != 'length') { - var ob1 = ob.childNodes[pName]; - if (ob1.nodeName == 'include') { - var tmplPath = ob1.getAttribute('templatePath'); + if (pName !== 'length') { + let ob1 = ob.childNodes[pName]; + if (ob1.nodeName === 'include') { + const tmplPath = ob1.getAttribute('templatePath'); if (tmplPath) { - var templString = fs.readFileSync(require.resolve(tmplPath)).toString(); - var templDoc = new DOMParser().parseFromString(templString); - ob.replaceChild(templDoc.firstChild, ob1) + const templString = fs.readFileSync(require.resolve(tmplPath)).toString(); + const templDoc = new DOMParser().parseFromString(templString); + ob.replaceChild(templDoc.firstChild, ob1); ob1 = ob.childNodes[i]; } } @@ -52,47 +48,43 @@ function getMaping(ob, fieldMapings) { } }); } else { - var nodeValue = ob.nodeValue; - var pat = /^\$\{(.*)}$/; - var res = nodeValue.match(pat); + const nodeValue = ob.nodeValue; + const pat = /^\$\{(.*)}$/; + const res = nodeValue.match(pat); if (res && res[1]) { - var path = []; - var attributes = {possNames: {}, explicitArray: false}; - var possNames = {}; - var explicitArray = false; + const path = []; + const attributes = { possNames: {}, explicitArray: false }; getPath(ob.parentNode, path, attributes); path.reverse(); - fieldMapings.push({path: path, fldName: res[1], possblNames: attributes.possNames, explicitArray: attributes.explicitArray}); - + fieldMapings.push({ path: path, fldName: res[1], possblNames: attributes.possNames, explicitArray: attributes.explicitArray }); } } } function extractValue(obbVal, path, pNames, resultObj, possNames, explicitArray) { - var lstName = pNames[(pNames.length - 1)]; + const lstName = pNames[(pNames.length - 1)]; - for (var i = 1; i <= path.length; i++) { - if (obbVal && !Array.isArray(obbVal) && explicitArray && i == (path.length - 1)) { + for (let i = 1; i <= path.length; i++) { + if (obbVal && !Array.isArray(obbVal) && explicitArray && i === (path.length - 1)) { obbVal = [obbVal]; } if (Array.isArray(obbVal)) { - - var childName = path.length == i ? lstName : (pNames.length == 1 ? 'data' : pNames[0]); + const childName = path.length === i ? lstName : (pNames.length === 1 ? 'data' : pNames[0]); resultObj[childName] = resultObj[childName] || []; - if ((path.length - 1) == i || path.length == i) { + if ((path.length - 1) === i || path.length === i) { obbVal.forEach(function(ar, ix) { - //var val = ar[path[i]] ? ar[path[i]] : ar; - if (typeof(ar[path[i]]) != 'undefined' || (typeof(path[i]) == 'undefined' && typeof(ar) == 'string')) { - // we enter here when there is such property in result object OR when result object i actualy array of string values - var val = removeNilValues(typeof(path[i]) != 'undefined' ? ar[path[i]] : ar); - if (path.length == i) { + // let val = ar[path[i]] ? ar[path[i]] : ar; + if (typeof (ar[path[i]]) !== 'undefined' || (typeof (path[i]) === 'undefined' && typeof (ar) === 'string')) { + // we enter here when there is such property in result object OR when result object i actualy array of string values + const val = removeNilValues(typeof (path[i]) !== 'undefined' ? ar[path[i]] : ar); + if (path.length === i) { resultObj[childName].push(val); - }else { + } else { if (resultObj[childName][ix]) { resultObj[childName][ix][lstName] = val; } else { - var vl = {}; + const vl = {}; vl[lstName] = val; resultObj[childName].push(vl); } @@ -100,19 +92,19 @@ function extractValue(obbVal, path, pNames, resultObj, possNames, explicitArray) } }); } else { - // todo: ...extract array sub objects - //var chOb = extractValue(ar[path[i]], path, pName); - //res.push(chOb); + // todo: ...extract array sub objects + // let chOb = extractValue(ar[path[i]], path, pName); + // res.push(chOb); } return resultObj; - } else if (typeof(obbVal) == 'object') { - var foundPn = false; + } else if (typeof (obbVal) === 'object') { + let foundPn = false; if (possNames[path[i]]) { - var posNames = possNames[path[i]]; - for (var p in posNames) { - if (typeof(posNames[p]) == 'string') { - if (posNames[p] == '*') { + const posNames = possNames[path[i]]; + for (const p in posNames) { + if (typeof (posNames[p]) === 'string') { + if (posNames[p] === '*') { obbVal = obbVal[Object.keys(obbVal)[0]]; foundPn = true; break; @@ -126,71 +118,65 @@ function extractValue(obbVal, path, pNames, resultObj, possNames, explicitArray) } } if (!foundPn) { - if (i == path.length) { + if (i === path.length) { resultObj[lstName] = obbVal[path[i]]; - }else { + } else { obbVal = obbVal[path[i]]; } } } else { - //text - if (pNames.length == 1) { + // text + if (pNames.length === 1) { resultObj[lstName] = obbVal; } else { if (!obbVal && explicitArray) { resultObj[pNames[0]] = resultObj[pNames[0]] || []; - }else { + } else { resultObj[pNames[0]] = resultObj[pNames[0]] || {}; resultObj[pNames[0]][lstName] = obbVal; } } } - } - } function tagNameProcessor(name) { - - var r = name.split(':'); + const r = name.split(':'); return r[r.length - 1]; } -////////////////////////////////////////////////////// - +// ---------------------------------------------- module.exports = { - - parse: function(templName, data){ - - var templFile = fs.readFileSync(require.resolve(templName)).toString(); - var doc = new DOMParser().parseFromString(templFile); - var fieldMapings = []; + parse: function(templName, data) { + const templFile = fs.readFileSync(require.resolve(templName)).toString(); + const doc = new DOMParser().parseFromString(templFile); + const fieldMapings = []; getMaping(doc, fieldMapings); return new Promise(function(resolve, reject) { - xml2js.parseString(data, {trim: true, - ignoreAttrs: false, - explicitArray: false, - tagNameProcessors: [tagNameProcessor] - }, - function(err, reslt) { - if(err){ - reject(err); - return; - } - var prsRes = {}; - for (var k in fieldMapings) { - if(typeof(fieldMapings[k]) == 'object') { - var path = fieldMapings[k].path; - var propNames = fieldMapings[k].fldName.split('.'); - var obbVal = reslt[path[0]]; - extractValue(obbVal, path, propNames, prsRes, fieldMapings[k].possblNames, fieldMapings[k].explicitArray); - } + xml2js.parseString(data, { + trim: true, + ignoreAttrs: false, + explicitArray: false, + tagNameProcessors: [tagNameProcessor] + }, + function(err, reslt) { + if (err) { + reject(err); + return; + } + const prsRes = {}; + for (const k in fieldMapings) { + if (typeof (fieldMapings[k]) === 'object') { + const path = fieldMapings[k].path; + const propNames = fieldMapings[k].fldName.split('.'); + const obbVal = reslt[path[0]]; + extractValue(obbVal, path, propNames, prsRes, fieldMapings[k].possblNames, fieldMapings[k].explicitArray); } - //console.log(reslt); - resolve(prsRes); } - ); + // console.log(reslt); + resolve(prsRes); + }); }); } -} \ No newline at end of file +}; From 8299a71df601d57d08db1a4afbcf91192d74c484 Mon Sep 17 00:00:00 2001 From: Jenkins CI Date: Thu, 3 Sep 2020 13:36:54 +0000 Subject: [PATCH 3/3] "chore(prerelease): [ci-skip] publish" - ut-function.xml2json@1.1.8-dfa-0.0 --- CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ packages/xml2json/package.json | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec77e15..e3852a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,33 @@ +# (2020-09-03) + + +### Bug Fixes + +* always cast parameters to strings before escaping ([#10](https://github.com/softwaregroup-bg/ut-function/issues/10)) ([cb8f6e2](https://github.com/softwaregroup-bg/ut-function/commit/cb8f6e295aa443ad6369b03a30fe4bd803032ff4)) +* cbc decrypt bad value handling ([4be5b91](https://github.com/softwaregroup-bg/ut-function/commit/4be5b91ebe06a068efd956bb8d894adde9c76bb1)) +* currency path ([15d2833](https://github.com/softwaregroup-bg/ut-function/commit/15d2833688dd08a001e36aadb411434141d8984d)) +* forgotten ([293de2f](https://github.com/softwaregroup-bg/ut-function/commit/293de2f149cd5086bb1781de9ddbef524ccf24a3)) +* handle \ and special chars in template ([34d8a9e](https://github.com/softwaregroup-bg/ut-function/commit/34d8a9e890c122642e6436330c767f747f3be22c)) + + +### Features + +* add flatten ([05754d3](https://github.com/softwaregroup-bg/ut-function/commit/05754d3bee861122afcdc6fb5c50a192f5bb1125)) +* add new module - ut-function.cbc ([fc2d346](https://github.com/softwaregroup-bg/ut-function/commit/fc2d346bfef073fa2e2e157a359deb4302aefcda)) +* add ut-function.dispatch ([a06b944](https://github.com/softwaregroup-bg/ut-function/commit/a06b94438790570768ef406ead83760ae4db0451)) +* additional packages - capture-hapi, capture-request, timezone ([#3](https://github.com/softwaregroup-bg/ut-function/issues/3)) ([9214235](https://github.com/softwaregroup-bg/ut-function/commit/92142352e69cefe02f1a0e9cca69d794f662cf0d)) +* curency ([3480eef](https://github.com/softwaregroup-bg/ut-function/commit/3480eefc72a3df7f551a83ccb10b031ab9cf1e50)) +* new package ut-function.equals ([#7](https://github.com/softwaregroup-bg/ut-function/issues/7)) ([0d55ffe](https://github.com/softwaregroup-bg/ut-function/commit/0d55ffe3d9fae9a5cdc2140100e6d771b42a7231)) +* new packege ut-function.interpolate ([#8](https://github.com/softwaregroup-bg/ut-function/issues/8)) ([f7bec27](https://github.com/softwaregroup-bg/ut-function/commit/f7bec27a469fa22b6ed6fc9e3c0229672a1d518b)) +* possibility to provide function as a merge handler ([a8cf31b](https://github.com/softwaregroup-bg/ut-function/commit/a8cf31b9424afbf5de03eb25685c7931c4c97afe)) +* recursive templating over objects ([#11](https://github.com/softwaregroup-bg/ut-function/issues/11)) ([483b7e4](https://github.com/softwaregroup-bg/ut-function/commit/483b7e4cb4d50906736122daba1d89481b307733)) +* return renderer function ([e517335](https://github.com/softwaregroup-bg/ut-function/commit/e51733518beffe579bbd1151bfe56f4e52812c8b)) +* simplify package names ([684a13d](https://github.com/softwaregroup-bg/ut-function/commit/684a13dc7d48b0396047d2935540b4618060b36f)) +* unit tests launcher, templates escaping ([#9](https://github.com/softwaregroup-bg/ut-function/issues/9)) ([6a72986](https://github.com/softwaregroup-bg/ut-function/commit/6a729867794a5d9c501c450205afd70bd28ad65e)) +* ut-function.xml2json ([a02838e](https://github.com/softwaregroup-bg/ut-function/commit/a02838ec659990a7afb84246c3ea943eb16f6555)) + + + # (2020-02-25) diff --git a/packages/xml2json/package.json b/packages/xml2json/package.json index 4582c7f..3e71dfe 100644 --- a/packages/xml2json/package.json +++ b/packages/xml2json/package.json @@ -1,6 +1,6 @@ { "name": "ut-function.xml2json", - "version": "1.1.7", + "version": "1.1.8-dfa-0.0", "description": "XML to JSON converter based on template", "dependencies": { "lodash.get": "4.4.2",