通过键将平面对象转换为嵌套结构

时间:2015-02-27 22:38:50

标签: javascript

在Javascript中是否有任何推荐的方法可以解析对象的键,将其转换为嵌套的东西?这是一个例子:

改变这个:

{
  "person[profile][0][degree_type]": "Bachelor's",
  "person[profile][0][college_name]": "AI Miami International University of Art and Design",
  "person[profile][0][business_school_name]": "",
  "person[profile][0][law_school_name]": "",
  "person[profile][0][other_school_name]": "",
  "person[profile][0][undergraduate_major_name]": "Anthropology",
  "person[profile][0][max_gpa]": "",
  "person[profile][1][degree_type]": "",
  "person[profile][1][college_name]": ""
}

对此:

"person": {
  "profile": [
    {
      "degree_type": "Bachelor's",
      "college_name": "AI Miami International University of Art and Design",
      "business_school_name": "",
      "law_school_name": "",
      "other_school_name": "",
      "undergraduate_major_name": "",
      "max_gpa": ""
    },
    {
      .....
    }
  ]
}

4 个答案:

答案 0 :(得分:2)

你走了! :)这很有趣。

var flatObj = {
  "person[profile][0][degree_type]": "Bachelor's",
  "person[profile][0][college_name]": "AI Miami International University of Art and Design",
  "person[profile][0][business_school_name]": "",
  "person[profile][0][law_school_name]": "",
  "person[profile][0][other_school_name]": "",
  "person[profile][0][undergraduate_major_name]": "Anthropology",
  "person[profile][0][max_gpa]": "",
  "person[profile][1][degree_type]": "",
  "person[profile][1][college_name]": ""
};

var parse = function(data, string, value) {
  if (string.indexOf("]") >= 0) {
    var match = string.charAt(0) != "[" ? string.match(/([^\[]+)\[/) : string.match(/\[([^\]]+)\]/);
    var key = match[1];

    var token = key + ']';
    var index = string.indexOf(token) + token.length;

    if (!data.hasOwnProperty(key)) {
      data[key] = isNaN(key) ? {} : [];
    }

    if (index >= string.length) {
      data[key] = value;
    } else {
      parse(data[key], string.substring(index), value);
    }
  }
};

var data = {};

for (var prop in flatObj) {
  parse(data, prop, flatObj[prop]);
}

答案 1 :(得分:1)

使用ES5 Object.keysarray.reduce方法,您可以使用以下内容:

var data = {
  "person[profile][0][degree_type]": "Bachelor's",
  "person[profile][0][college_name]": "AI Miami International University of Art and Design",
  "person[profile][0][business_school_name]": "",
  "person[profile][0][law_school_name]": "",
  "person[profile][0][other_school_name]": "",
  "person[profile][0][undergraduate_major_name]": "Anthropology",
  "person[profile][0][max_gpa]": "",
  "person[profile][1][degree_type]": "",
  "person[profile][1][college_name]": ""
};

var object = Object.keys(data).reduce(function(result, item) {
  var o = result;
  var leaf = item.match(/\w+/g).reduce(function(current, next) {
    o[current] = o[current] || (String(next >>> 0) === next ? [] : {});
    o = o[current];
    return next;
  });
  o[leaf] = data[item];
  return result;
}, {});

零填充右移运算符(>>>)用于模仿JS中的内部ToUint32运算,以确保字符串是有效数组的索引,否则被认为是property(例如"1.5"可以解析为数字,但不是有效数组的索引)。见ECMAScript specs section 15.4

答案 2 :(得分:0)

这绝对是矫枉过正的,但是这里有一个关于你如何通过用传统的词法分析器来理解你的关键语法的例子。优点是具有良好的错误报告以及易于增强语法。

以下是您可以通过以下方式获得的语法错误示例:

expandKeys({"person[profile][0]degree_type]": "Bachelor's" });

Uncaught Error: invalid key 'person[profile][0]degree_type]'; expected '[' and instead saw 'd' at character 18



/*jshint esnext:true*/
var expandKeys = (function () {
    'use strict';
    
    var LBRACK = '[',
        RBRACK = ']';
    
    return function (obj) {
        var result = {};
        
        Object.keys(obj).forEach(function (k) {
            var tokens = tokensFrom(k), 
                o = result,
                t = nextFrom(tokens, k).value;
            
            while (t) {
                let next = nextFrom(tokens, k);                
                if (next.done) o[t] = obj[k];
                else if (o.hasOwnProperty(t)) o = o[t];
                else o = o[t] = isInt(+next.value)? [] : {};
                t = next.value;
            }
        });
                
        return result;
    };
    
    function isInt(val) {
        return val >>> 0 === val;
    }
    
    function nextFrom(gen, k) {
        try {
            return gen.next();
        } catch (e) {
            throw new Error("invalid key '" + k + "'; " + e.message);
        }
    }
    
function *tokensFrom(input) {
        var state = prop, 
            i = 0, 
            c = input[0],
            token;
        
        while (state = state()) yield token;
        
        yield token;
        
        function prop() {
            var p = '';
            
            while (c && c !== LBRACK && c !== RBRACK) {
                p += c;
                consume();
            }
            
            if (!p) error('expected a property name');
            
            token = p;
            
            return c? surroundedProp : null;
        }
        
        function surroundedProp() {
            match(LBRACK);
            prop();
            match(RBRACK);
            return c? surroundedProp : null;
        }
        
        function match(char) {
            if (c === char) consume();
            else error("expected '" + char + "' and instead saw '" + (c || '') + "'");
        }
        
        function consume() {
            return c = input[++i];
        }
        
        function error(msg) {
            throw new Error(msg + ' at character ' + i);
        }
    }
    
})();

var data = {
    "person[profile][0][degree_type]": "Bachelor's",
    "person[profile][0][college_name]": "AI Miami International University of Art and Design",
    "person[profile][0][business_school_name]": "",
    "person[profile][0][law_school_name]": "",
    "person[profile][0][other_school_name]": "",
    "person[profile][0][undergraduate_major_name]": "Anthropology",
    "person[profile][0][max_gpa]": "",
    "person[profile][1][degree_type]": "",
    "person[profile][1][college_name]": ""
};


var result = expandKeys(data),
    resultJson = JSON.stringify(result, null, 2),
    pre = document.createElement('pre');

pre.textContent = resultJson;

document.body.appendChild(pre);




答案 3 :(得分:0)

如果您碰巧正在使用ramda.js,则这是一小段代码

const obj = {
  'nestedObject[first]': 10,
  'nestedObject[second]': 5,
  'nestedArray[0]': 3.1,
  'nestedArray[1]': 3.2,
  'param': 5
}

const deFlatten = (object) => {
  const parsePath = R.pipe(R.match(/(\w+)/g), R.map(R.ifElse(R.pipe(R.unary(parseInt), isNaN), R.identity, R.unary(parseInt))));
  const reducer = (acc, flatKey) => R.set(R.lensPath(parsePath(flatKey)), object[flatKey])(acc);
  return R.pipe(R.keys, R.reduce(reducer, {}))(object);
};

console.log(deFlatten(obj));
<script src="https://cdn.jsdelivr.net/npm/ramda@0.25.0/dist/ramda.min.js"></script>