从嵌套的JSON构建键值数组

时间:2015-05-18 09:40:44

标签: javascript arrays json recursion

我有以下JSON对象。我需要将它在javascript中转换为一级关联数组。 (键值对)我写了一个递归函数,但似乎无法按照我想要的方式工作。

{
    "Title" : "Test Match",
    "Players" : [
        {
            "ID" : 1,
            "Name" : "Igi Manaloto",
            "Results" : [2,2,0],
            "TeamMates" : [
                {
                    "ID" : 2,
                    "Name" : "John Ibarra",
                    "Age" : 24,
                    "LikesToWin" : false
                }
            ]
        }, {
            "ID" : 22,
            "Name" : "Shawn Kato",
            "Results" : [2,1,0],
            "TeamMates" : [
                {
                    "Name" : "Gerald Anderson",
                    "Age" : 24,
                    "LikesToWin" : false
                }
            ]
        }
    ],
    "Referees" : [
        {
            "ID" : 10,
            "Name" : "Janice Tieu",
            "YearsAsReferee" : 10,
            "EmploymentHistory" : [
                {
                    "JobTitle" : "Senior Referee",
                    "YearsOnTheJob" : 20,
                    "FavouriteMatchesRefereeed" : [
                        {
                            "Title" : "Duran vs Leonard 1",
                            "Year" : 1992,
                            "Description" : "I was refereeing the test match but I put on make up so Duran lost the bout."
                        }, {
                            "Title" : "Duran vs Leonard 2",
                            "Year" : 1994,
                            "Description" : "I was refereeing the second match but I put on make up so Duran lost another bout."
                        }
                    ]
                }, {
                    "JobTitle" : "Juniour Refereee",
                    "YearsOnTheJob" : 3,
                    "FavouriteMatchesRefereeed" : [
                        {
                            "Title" : "Mexican Figher Jones vs Anna Himley",
                            "Year" : 1972,
                            "Description" : "I coached this match. Hehe."
                        }, {
                            "Title" : "Jennifer from the block 2",
                            "Year" : 1982,
                            "Description" : "I coached this other match. Hehe."
                        }
                    ]
                }
            ]
        }
    ]
}

下面预期的关联数组示例:

[
    "Title" => "Test Match",
    "Players[0][ID]" => 0,
    "Players[0][Name]" => "Igi Manaloto",
    // rest of the array...
    "Players[0][Teammates][0][ID]" => 2,
    "Players[0][Teammates][0][Name]" => "John Ibarra",
    // rest of the array...
    "Referees[0][EmploymentHistory][FavouriteMatchesRefereeed][Title]" => "Duran vs Leonard 1"
]

这是我迄今为止所做的(javascript)

function converJSONToStrings(values, prevParent){
    console.log(values);
    var result = [];    

    for (var key in values)
    {
        var value = values[key];
        if(value.constructor === Array) {
            // console.log("Found object array in key", key );
            for(var x = 0; x<value.length; x++){
                result[key + '[' + x + ']'] = converJSONToStrings(value[x]);
            }
        } else if (typeof value == 'object') {
            for(var x in value){
                result[key + '[' + x + ']'] = converJSONToStrings(value[x]);
            }
        } else {
            result[key] = value;
        }
    }    

    return result;
}

2 个答案:

答案 0 :(得分:1)

终于想出了一个解决方案!代码如下......

 /** 
  * Formats the JSON result to an associative array, concatenating child and parent keys 
  */
 var convertJSONAssoc = function(obj, firstlevel) {
     // consider string, number and boolean values in JSON as the last
     // elements and can't be recursed into any further
     if (typeof obj == 'string' || typeof obj == 'number' || typeof obj == 'boolean') {
         var ab = [];
         var bc = {};
         bc.key = '';
         bc.val = obj;
         ab.push(bc);
         return ab;
     }

     // the top most call which builds the final result
     if (firstlevel) {
         var result = {};
         for (key in obj) {
             var val = obj[key];
             var s = convertJSONAssoc(val, false);
             for (var o = 0; o < s.length; o++) {
                 var v = s[o];
                 result[key + v['key']] = v['val'];
             }
         }
         return result;
     } else {
         // this is where the recursion happens. As long as objects are found,
         // we use the code below to keep on parsing obj keys
         var paths = [];
         for (var key in obj) {
             var val = obj[key];
             var s = convertJSONAssoc(val, false);
             for (var o = 0; o < s.length; o++) {
                 var v = s[o];
                 var de = {};
                 de.key = "[" + key + "]" + v['key'];
                 de.val = v['val'];
                 paths.push(de);
             }
         }
         return paths;
     }
 }

答案 1 :(得分:1)

这是一个老问题,由于 OP 的编辑而重新出现。现代技术使这比编写问题时更容易一些。

这使用了两个函数。 pathEntries 我过去常常将对象转换为我认为更有用的类似格式,例如

[
  [['Title'], 'Test Match'],
  [['Players', 0, 'ID'], 1],
  [['Players', 0, 'Name'], 'Ma Couella,
  // ...
  [['Referees', 0, 'EmploymentHistory', 1, 'FavouriteMatchesRefereeed', 1, 'Year'], 1982],
  [['Referees', 0, 'EmploymentHistory', 1, 'FavouriteMatchesRefereeed', 1, 'Description'], 'I coached this other match. Hehe.']
]

然后 convert,结合键映射和 Object.fromEntries(如果您需要支持没有它的环境,这很容易填充),将其转换为您需要的格式。它看起来像这样:

const pathEntries = (obj) =>
  Object (obj) === obj
    ? Object .entries (obj) .flatMap (
        ([k, x]) => pathEntries (x) .map (([p, v]) => [[k, ... p], v])
      ) 
    : [[[], obj]]
  

const convert = (obj) => 
  Object .fromEntries (
    pathEntries (obj) .map (([k, v]) => [
      k[0] + k .slice (1) .map (n => `[${n}]`) .join (''), 
      v
    ])
  )

            
const data = {Title: "Test Match", Players: [{ID: 1, Name: "Ma Couella", Results: [2, 2, 0], TeamMates: [{ID: 2, Age: 24, LikesToWin: !1}]}, {ID: 22, Name: "Shawn Kato", Results: [2, 1, 0], TeamMates: [{Name: "Gerald Anderson", Age: 24, LikesToWin: !1}]}], Referees: [{ID: 10, Name: "Janice Tieu", YearsAsReferee: 10, EmploymentHistory: [{JobTitle: "Senior Referee", YearsOnTheJob: 20, FavouriteMatchesRefereeed: [{Title: "Duran vs Leonard 1", Year: 1992, Description: "I was refereeing the test match but I put on make up so Duran lost the bout."}, {Title: "Duran vs Leonard 2", Year: 1994, Description: "I was refereeing the second match but I put on make up so Duran lost another bout."}]}, {JobTitle: "Juniour Refereee", YearsOnTheJob: 3, FavouriteMatchesRefereeed: [{Title: "Mexican Figher Jones vs Anna Himley", Year: 1972, Description: "I coached this match. Hehe."}, {Title: "Jennifer from the block 2", Year: 1982, Description: "I coached this other match. Hehe."}]}]}]}

console .log (convert (data))
.as-console-wrapper {max-height: 100% !important; top: 0}

注意 I often write pathEntries 就更简单的 getPathspath 函数而言。这更简洁但效率较低,因为它需要对对象进行额外的遍历。