diff --git a/401-DataExtractor.html b/401-DataExtractor.html new file mode 100644 index 00000000..e5603f4d --- /dev/null +++ b/401-DataExtractor.html @@ -0,0 +1,572 @@ + + + + + + + \ No newline at end of file diff --git a/401-DataExtractor.js b/401-DataExtractor.js new file mode 100644 index 00000000..1f320142 --- /dev/null +++ b/401-DataExtractor.js @@ -0,0 +1,229 @@ +module.exports = function (RED) { + const xml2js = require('xml2js'); + const parseString = xml2js.parseString; + const options = { + explicitArray: false, + }; + + let result = []; + + function DataExtractor(config) { + RED.nodes.createNode(this, config); + let node = this; + + node.on("input", function (msg) { + try { + let data; + if (config.response_type === "json") { + data = JSON.parse(msg.payload); + } else { + parseString(msg.payload, options, (err, result) => { + if (err) { + node.error(err, msg); + } else { + data = result; + } + }); + } + let paths = config.paths; + + if (paths.length === 0) { + result = ''; + } else { + result = [paths]; + formatJSON(data, paths); + } + msg.payload = result; + node.send(msg); + } catch (error) { + msg.payload = "Unknown error"; + node.error(error.toString(), msg); + } + }); + } + + function formatJSON(json, paths) { + if (typeof json === "string") { + json = JSON.parse(json); + } + if (!(paths instanceof Array)) { + paths = [paths]; + } + paths.forEach((path) => { + path = path.split("."); + resultOnlyOne = { + [path[path.length - 1]]: formatJSONOnlyOne(json, path) + } + result.push(resultOnlyOne); + }); + if (result.length === 2) { + result = result[1]; + } + } + + function formatJSONOnlyOne(data, path) { + key = path.shift(); + if (key === undefined) return data; + try { + if (data[key] === undefined) { + return path.length ? `Invalid Key : ${key}` : undefined; + } + if (data[key] instanceof Array) { + const valArray = []; + for (item of data[key]) { + valArray.push(formatJSONOnlyOne(item, [...path])); + } + return valArray; + } + return formatJSONOnlyOne(data[key], path); + } catch (error) { + return `Unknown Error`; + } + } + + function DataFilter(config) { + RED.nodes.createNode(this, config); + let node = this; + + node.on("input", function (msg) { + try { + let data; + if (config.response_type === "json") { + data = JSON.parse(msg.payload); + } else { + parseString(msg.payload, options, (err, result) => { + if (err) { + node.error(err, msg); + } else { + data = result; + } + }); + } + targetArr = []; + + let input = { + data: data, + stdPath: config.stdPath, + stdValue: config.value, + stdType: config.value_type, + outputPaths: config.outputPaths, + }; + + findTarget(input); + + const cleanedOutputPaths = input.outputPaths.map((path) => cleanPath(path, input.stdPath)); + + let result = []; + targetArr.forEach((target) => { + let ret = {}; + cleanedOutputPaths.forEach((path) => { + makeResult(ret, target, [...path]); + }); + result.push(ret); + }); + + if (result.length === 1) { + result = result[0]; + } + + msg.payload = result; + node.send(msg); + } catch (error) { + node.error(error.toString(), msg); + } + }); + } + + function compareData(data, stdValue, stdType) { + if (data === undefined || data === null || stdValue === undefined || stdValue === null) { + return false; + } + if (stdType === "str") { + return data.toString() === stdValue; + } + if (stdType === "num") { + if (isNaN(data) || isNaN(stdValue)) { + return false; + } + return data.toString() === stdValue; + } + if (stdType === "bool") { + return data.toString().toLowerCase() === stdValue; + } + return false; + } + + function findTarget(input) { + stdPath = input.stdPath.split("."); + findTargetOnlyOne(input.data, stdPath, input.stdValue, input.stdType); + } + + function findTargetOnlyOne(data, path, stdValue, stdType) { + if (path.length === 1) { + if (compareData(data[path], stdValue, stdType)) { + targetArr.push(data); + return; + } + } + + let key = path.shift(); + try { + if (data[key] === undefined) { + return; + } + if (data[key] instanceof Array) { + for (let item of data[key]) { + findTargetOnlyOne(item, [...path], stdValue, stdType); + } + } + findTargetOnlyOne(data[key], path, stdValue, stdType); + } catch (error) { + console.log(`Unknown Error`); + } + } + + function cleanPath(path, stdPath) { + let paths = path.split("."); + let stdPaths = stdPath.split("."); + + while (stdPaths.length > 1) { + paths.shift(); + stdPaths.shift(); + } + return paths; + } + + function makeResult(ret, target, path) { + if (path.legnth < 1) { + return; + } + + if (path.length == 1) { + ret[path[0]] = target[path[0]]; + return; + } + + let key = path.shift(); + if (target[key] instanceof Array) { + if (ret[key] === undefined) { + ret[key] = []; + } + for (let i = 0; i < target[key].length; i++) { + if (ret[key][i] === undefined) { + ret[key].push({}); + } + makeResult(ret[key][i], target[key][i], [...path]); + } + return; + } + + if (ret[key] === undefined) { + ret[key] = {}; + } + makeResult(ret[key], target[key], [...path]); + } + + RED.nodes.registerType("data-extractor", DataExtractor); + + RED.nodes.registerType("data-filter", DataFilter); +}; diff --git a/package.json b/package.json index aec191ee..67b06c5b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red-contrib-samsung-automation-studio-nodes", - "version": "1.1.16", + "version": "1.1.17", "description": "Samsung Automation Studio Nodes for Node-RED", "keywords": [ "SmartThings", @@ -21,7 +21,8 @@ "Auth": "201-Basicauth.js", "AWS": "301-AWS.js", "DB": "302-DB.js", - "SlackNotification": "303-SlackNotification.js" + "SlackNotification": "303-SlackNotification.js", + "DataExtractor": "401-DataExtractor.js" } }, "dependencies": { @@ -38,7 +39,8 @@ "on-headers": "^1.0.2", "pg": "^8.3.0", "proxy-agent": "^5.0", - "when": "3.7.8" + "when": "3.7.8", + "xml2js": "^0.6.2" }, "devDependencies": { "grunt": "^1.6.1"