自动将json属性解析为新对象

时间:2017-11-13 07:16:21

标签: javascript json node.js

我有json格式的传入数据,如下所示:

原始数据

{
  "data": [{
      "id": "Device_6",
      "type": "SensingDevice",
      "Battery": {
        "type": "Number",
        "value": "4.08",
        "metadata": {
          "timestamp": {
            "type": "DateTime",
            "value": "2017-11-09T14:49:02.00Z"
          },
          "unit": {
            "type": "Text",
            "value": "voltage"
          }
        }
      },
      "DO": {
        "type": "Number",
        "value": "5.71",
        "metadata": {
          "timestamp": {
            "type": "DateTime",
            "value": "2017-11-09T14:49:02.00Z"
          },
          "unit": {
            "type": "Text",
            "value": "mg/l"
          }
        }
      },
      "Humidity": {
        "type": "Number",
        "value": "57.30",
        "metadata": {
          "timestamp": {
            "type": "DateTime",
            "value": "2017-11-09T14:49:02.00Z"
          },
          "unit": {
            "type": "Text",
            "value": "percent"
          }
        }
      },
      "PH": {
        "type": "Number",
        "value": "14.00",
        "metadata": {
          "timestamp": {
            "type": "DateTime",
            "value": "2017-11-09T14:49:02.00Z"
          }
        }
      },
      "temperature": {
        "type": "Number",
        "value": "41.00",
        "metadata": {
          "timestamp": {
            "type": "DateTime",
            "value": "2017-11-09T14:49:02.00Z"
          },
          "unit": {
            "type": "Text",
            "value": "celsius"
          }
        }
      },
      "waterTemperature": {
        "type": "Number",
        "value": "29.69",
        "metadata": {
          "timestamp": {
            "type": "DateTime",
            "value": "2017-11-09T14:49:02.00Z"
          },
          "unit": {
            "type": "Text",
            "value": "celsius"
          }
        }
      }
    }
  ],
  "subscriptionId": "59d5eeec4f3db340052d618c"
}

出于特定的应用目的,我需要将此复杂JSON转换为简单的key:value格式。

所以我在节点js中使用node-json-transform包中的代码:

 var map_data = {
           list:'data',
            item :  { Battery: 'Battery.value',
                        DO: 'DO.value',
                        Humidity: 'Humidity.value',
                        PH: 'PH.value',
                        temperature: 'temperature.value',
                        waterTemperature: 'waterTemperature.value', },
    };
   console.log (map_data)

         var dataTransform = DataTransform(data, map_data);
         var data_result = dataTransform.transform();

输出看起来像我想要的那样:

[ { Battery: '4.08',
    DO: '5.71',
    Humidity: '57.30',
    PH: '14.00',
    temperature: '41.00',
    waterTemperature: '29.69' } ]

但是现在,如果我不知道属性的名称怎么办? 所以我试着让它自动发现键:

var keys = Object.keys(data.data[0]); 
var keysvalues = '';
    for (i=2; i < keys.length; i++) {
        keysvalues += keys[i]+':"'+ keys[i] + '.value",';
    }
var item = '{'+keysvalues+'}'; 
var map_data = {
            list:"data", 
            item,
    };
 var dataTransform = DataTransform(data, map_data);
 var data_result = dataTransform.transform();

这不起作用,因为对象map_data.item是一个“假”对象,我手动添加{},因此它被识别为字符串:

console.log(map_data)
{ list: 'data',
  item: '{Battery:"Battery.value",DO:"DO.value",Humidity:"Humidity.value",PH:"PH.value",temperature:"temperature.value",waterTemperature:"waterTemperature.value",}' } 

你能帮助我如何使项目对象成为一个真实的对象,这样我就能以我想要的格式自动解析JSON吗?

2 个答案:

答案 0 :(得分:2)

所以基本上你想创建一个给定所有嵌套对象的'value'属性的地图。这意味着您必须过滤掉原始对象中不是“对象”或没有“值”支柱的键。 这是我将如何做到的(我使用ES6来避免冗长)。

const isObject = (o) =>
  o instanceof Object && o.constructor === Object;

const getSingleMap = (datum, prop) => {
  const mapKeys = Object.keys(datum).filter(key => isObject(datum[key]) && datum[key][prop]);
  const obj = {};
  mapKeys.forEach(key => {
    obj[key] = datum[key][prop];
  });

  return obj;
}

const getMap = (rawData, prop) =>
  rawData.data.map(datum => getSingleMap(datum, prop));

要使用它,只需拨打const res = getMap(rawData, 'value');

/*
res == [
  {
    "Battery": "4.08",
    "DO": "5.71",
    "Humidity": "57.30",
    "PH": "14.00",
    "temperature": "41.00",
    "waterTemperature": "29.69"
  }
];
*/

下面提供了一个更优雅的getSingleMap实现。

getSingleMap = (datum, prop) => {
  const mapKeys = Object.keys(datum).filter(key => isObject(datum[key]) && datum[key][prop]);
  return mapKeys.reduce((acc, key) => {
    acc[key] = datum[key][prop];
    return acc;
  }, {});
}

更新:我还创建了一个npm包,它叫做 json2kv ,你可以找到它的来源here

答案 1 :(得分:-1)

原始JavaScript代码 可以更改if约束以处理 数组 如果您的DATA字段不是数组,它将无法处理数组

如果你的json中有数组,它将非常复杂(不仅仅是关于你想要的结果的代码)。 另一个问题是key : value格式将覆盖您的许多信息

但是如果您想以任何方式执行此操作,只需执行以下操作:

  function ToSimpleJson(json , result , prefix)
{
   for(key in json)
   {
       if(typeof json[key]!="object" )
           result[prefix+key] = json[key]
       else if (!json[key].length) // Object
           ToSimpleJson(json[key], result , (key+"."))
       else // Array (But will Override if have more than 1 index)
       {
           json[key].forEach(function (x)
           {    
               ToSimpleJson(x, result , (key + "."))
           })

       }
   }

return result
}

并使用空结果和空前缀

调用函数
ToSimpleJson(json , {} , "")

结果是:

{
    "data.id" : "Device_6",
    "data.type" : "SensingDevice",
    "Battery.type" : "Number",
    "Battery.value" : "4.08",
    "timestamp.type" : "DateTime",
    "timestamp.value" : "2017-11-09T14:49:02.00Z",
    "unit.type" : "Text",
    "unit.value" : "celsius",
    "DO.type" : "Number",
    "DO.value" : "5.71",
    "Humidity.type" : "Number",
    "Humidity.value" : "57.30",
    "PH.type" : "Number",
    "PH.value" : "14.00",
    "temperature.type" : "Number",
    "temperature.value" : "41.00",
    "waterTemperature.type" : "Number",
    "waterTemperature.value" : "29.69",
    "subscriptionId" : "59d5eeec4f3db340052d618c"
}