在jQuery中使用动态对象名称重新格式化JSON

Reformat JSON with dynamic object names in jQuery

本文关键字:格式化 JSON 对象 jQuery 动态      更新时间:2023-09-26

我有一组简单的JSON需要重新格式化,因为所有的键值对并不总是输出。

{
"result": [
    {
        "category": "Negative Notification",
        "event": "open",
        "result": 2
    },
    {
        "category": "Referral",
        "event": "bounce",
        "result": 1
    },
    {
        "category": "Negative Notification",
        "event": "delivered",
        "result": 34
    },
    {
        "category": "Negative Notification",
        "event": "processed",
        "result": 34
    },
    {
        "category": "Positive Notification",
        "event": "open",
        "result": 42
    },
    {
        "category": "Referral",
        "event": "delivered",
        "result": 17
    },
    {
        "category": "Positive Notification",
        "event": "processed",
        "result": 504
    },
    {
        "category": "Referral",
        "event": "processed",
        "result": 18
    },
    {
        "category": "Positive Notification",
        "event": "delivered",
        "result": 504
    },
    {
        "category": "Negative Notification",
        "event": "bounce",
        "result": 16
    },
    {
        "category": "Positive Notification",
        "event": "bounce",
        "result": 176
    },
    {
        "category": "Referral",
        "event": "open",
        "result": 10
    }
]
}

输出方式的问题取决于数据是否可用,按数字访问对象可能会创建意想不到的功能。第二个问题是,它必须由javascript操作,而不能在服务器端操作。

我希望JSON被重新格式化,以便每个类别都是一个对象(目前有三个,但可能多达五个),对象内汇总了数据。例如:

{
"result": {
    "Negative Notification" : [ 
        {
        "processed":34,
        "delivered":34,
        "bounces":16,
        "opens":2
        }
    ],
    "Positive Notification" : [
        {
        "processed":504,
        "delivered":504,
        "bounces":176,
        "opens":42
        }
    ],
    "Referral" : [
        {
        "processed":18,
        "delivered":17,
        "bounces":1,
        "opens":10
        }
    ]
}
}

我该怎么做?简单地循环遍历并命名对象并没有给我带来任何结果。

作为t.j. Crowder建议的补充:相同的基本原则,只是不依赖于ES5功能,也不需要垫片。注意:这个解决方案与"期望的输出"在一个方面有所不同:而不是让每个类别引用一个只有一个元素的数组(对象字面量),我只是直接为它分配一个对象字面量。您想要的格式将要求您像这样访问被跳转的引用:obj.result.Referral[0].bounces,而我认为如果它是obj.result.Referral.bounces,而不包含数组,则更有意义。

//suppose a is the raw JSON data
var b = {result:{}};//this will become be the object you want
for (var i=0;i<a.result.length;i++)
{
    b.result[a.result[i].category] = (function(obj)
    {
        var p, res = {};
        for (p in obj)
        {
            if (p !== 'category' && obj.hasOwnProperty(p))
            {
                res[p] = obj[p];
            }
        }
        return res;
    }(a.result[i]));
}

这个循环遍历由a.result引用的数组,每次使用a.result[i].category的值作为保存其他数据的对象的属性名。
结果是:

console.log(JSON.stringify(b));
{"result":
    {"Negative Notification":
        {"event":"bounce",
         "result":16},
    "Referral":
        {"event":"open",
         "result":10},
    "Positive Notification":
        {"event":"bounce","result":176}
    }
}

但是真的:为什么不在发送之前格式化数据呢?如果您可以访问输出该数据的代码,请更改该代码以更好地满足您的需求。

编辑:
对于你的评论,我认为你真正想要的是:

var b={result{}};
for (i=0;i<a.result.length;i++)
{
    b.result[a.result[i].category] = b.result[a.result[i].category] || {};//use existing, or create new object
    b.result[a.result[i].category][a.result[i].event] = a.result[i].result;//add property for event type, assign value
}

在这段代码运行之后,对象b看起来像这样:

{"result":
    {"Negative Notification":
        {"open":2,
         "delivered":34,
         "processed":34,
         "bounce":16},
      "Referral":
        {"bounce":1,
         "delivered":17,
         "processed":18,
         "open":10},
      "Positive Notification":
         {"open":42,
          "processed":504,
          "delivered":504,
          "bounce":176}
     }
}

这意味着,您可以使用b.result.Referral.bounce而不是使用b.result.Referral[0].bounce。但更重要的是,一开始就不需要result属性:

var result ={};
for (i=0;i<a.result.length;i++)
{
    result[a.result[i].category] = result[a.result[i].category] || {};
    result[a.result[i].category][a.result[i].event] = a.result[i].result;
}
console.log(result);
{"Negative Notification":
    {"open":2,
     "delivered":34,
     "processed":34,
     "bounce":16},
  "Referral":
    {"bounce":1,
     "delivered":17,
     "processed":18,
     "open":10},
  "Positive Notification":
     {"open":42,
      "processed":504,
      "delivered":504,
      "bounce":176}
 }

简单地循环遍历并命名对象是行不通的。

然而,这正是你需要做的。:-)可能把它们写到不同的对象。

示例:Live Example | Source

// The object that will contain the result
var obj = {};
// Loop through the `result` array on your object
yourObject.result.forEach(function(element) {
    // See if we already have an entry for that category
    var entry = obj[element.category];
    if (!entry) {
        // We don't, so create a blank array for it
        entry = obj[element.category] = [];
    }
    // Push this entry in the category's array
    entry.push(element);
});

这只是它的骨架,你需要做的是把弹跳加起来。但这应该是你开始…

以上依赖于ES5的forEach函数。如果你需要支持不支持它的浏览器,你可以应用一个"ES5 shim"。