2013-05-06 3 views
0

У меня есть простой набор JSON, который нужно переформатировать, поскольку все пары значений ключей не всегда выводятся.Reformat JSON с динамическими именами объектов в jQuery

{ 
"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 
     } 
    ] 

} 
} 

Как бы снять это? Простое перемещение и называние объектов никуда не ведет.

ответ

2

В дополнение к предложению T.J Кроудера: тот же базовый принцип, только не полагаясь на функцию ES5 и не требующий прокладки. Примечание: Это решение отличается от вашего «желаемым результатом» в одном виде: вместо того, чтобы иметь ссылку на каждую категорию массива, который имеет только 1 элемент (литерал объекта), я просто назначаю ему литерал объекта напрямую. Ваш желаемый формат потребует, чтобы вы получили доступ к возвращенным рефералам следующим образом: 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} 
    } 
} 

Но на самом деле: почему бы не форматировать данные перед тем вы отправляете его, если у вас есть доступ к коду, который выводит эти данные, изменить этот код, чтобы лучше в отелях.

Edit:
В ответ на ваш комментарий, я думаю, что вы на самом деле после того, как это:

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[0].bounce вы можете использовать b.result.Referral.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} 
} 
+0

У меня нет доступа к системе, которая выводит данные. Как бы вы получили все данные внутри этого? – Taylor

+0

@ Тейлор: не может победить всех ... Тогда вам придется использовать либо мой ответ, либо TJ Crowders, либо объединить два (как в случае использования массива, просто использовать литералы объектов) –

+0

Спасибо за Помогите. Я посмотрю, смогу ли я закончить это и получить оставшиеся элементы для вывода. Существует преимущество в том, чтобы упростить имена событий ex: {"bounce": 16}, любые идеи о том, как это сделать? – Taylor

0

Простое перемещение и называние объектов ведет меня никуда.

И все же, это именно то, что вам нужно сделать. :-) Наверное, записывая их на другой объект.

0 Например: 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».

+0

Где он размещает элементы в объекте? – Taylor

+0

@Taylor: 'entry = obj [element.category] = [];' создает запись в 'obj' с именем свойства в' element.category' и присваивает ему пустой массив. Позже мы добавляем записи в массив taht через 'entry.push'. –