【问题标题】:How to convert FormData to JSON recursively (retaining the hierarchy)?如何递归地将 FormData 转换为 JSON(保留层次结构)?
【发布时间】:2021-12-31 12:27:19
【问题描述】:

我知道这里还有其他问题,但没有一个解决这个特定问题。


当我们有这样的形式时:

<input name="A" .. />
<input name="B[x1]" .. />
<input name="C[y][z]".. />

然后所有解决方案建议 here 只需创建平面层次结构 JSON,例如:

{
   "A" : "1",
   "B[x1]" : "2" 
}

但是,它需要创建的正确表单数据应该是:

{
   "A" : "1",
   "B" : {
      "x1":"2
   }
}

是否有任何标准/内置的 JS 方法?

【问题讨论】:

  • 没有内置函数,但我想你可以修改答案来做你想做的事?
  • 解决方案让你更接近你想要的stackoverflow.com/a/53245088/1175966
  • 我怀疑那里可能有一个图书馆可以做到这一点,但不确定它是什么。 QS library 可能会有所帮助。看它的parse方法
  • @charlietfl 感谢您的回答,非常感谢。我试过调查,它似乎有点大/复杂的代码(虽然可能是先进和复杂的),而 ATM,我更喜欢我在下面发布的自定义函数。

标签: javascript json forms


【解决方案1】:

令人惊讶,但是 JS 没有任何原生/通用的方式来实现这个目标。临时解决方案(注意,这没有经过广泛测试)我为我做的需要:

function formItemsToJson(FormElement){    
    let formDataEntries = new FormData(FormElement).entries();
    const handleChild = function (obj,keysArr,value){
        let firstK = keysArr.shift();
        firstK=firstK.replace(']','');
        if (keysArr.length==0){
            if (firstK=='') {
                if (!Array.isArray(obj)) obj=[];
                obj.push(value);
            }
            else obj[firstK] = value; 
        } 
        else{
            if (firstK=='') obj.push(value); 
            else {
                if ( ! ( firstK in obj) ) obj[firstK]={};
                obj[firstK] = handleChild(obj[firstK],keysArr,value);
            }
        }
        return obj;
    };
    let result = {};
    for (const [key, value]  of formDataEntries )
        result= handleChild(result, key.split(/\[/), value); 
    return result;
}


// USAGE :  
alert( JSON.stringify( formItemsToJson( document.querySelector('#myForm') ), null, 2 ) );
<form id="myForm">
    <input type="hidden" name="A" value="11" />
    <input type="hidden" name="C[E][m1]" value="22" />
    <input type="hidden" name="C[E][m2]" value="23" />

    <!-- only FormData can parse this below, because with JSON.stringify the below object will degrade,as same keys will be in conflict  -->
    <input type="hidden" name="Y[Z][]" value="101" />
    <input type="hidden" name="Y[Z][]" value="102" />
</form>

【讨论】:

  • 如果函数转换为 json 为什么不把它里面的 stringify 也拿出来呢?这样它实际上会返回 json
  • @evolutionxbox 相同的键 (Y[Z][]) 会发生冲突,似乎只有 FormData 可以处理它们。
【解决方案2】:

使用Object.fromEntries 迭代条目
每个循环抓取 key : value。如果key 不包含[ 将其添加到对象res,否则获取该键的旧值(对象) e.i. B 并将它们添加到当前及其值。
我们也可以使用 Regex 来动态获取嵌套的键和值,而不是 indexOf

const obj = {
  A: "1",
  "B[x1]": "2",
  "B[x2]": "3",
};
res = {};
Object.entries(obj).forEach((entry) => {
  const [key, value] = entry;
  if (!key.includes("[")) res[key] = value;
  else {
    const parentKey = key.slice(0, key.indexOf("["));
    const childKey = key.slice(key.indexOf("[") + 1, -1);
    res[parentKey] = res[parentKey] ?? [];
    res[parentKey].push({ [childKey]: value });
  }
});
res; //?

Result:

{
  "A": "1",
  "B": [
    {
      "x1": "2"
    },
    {
      "x2": "3"
    }
  ]
}

【讨论】:

  • 我已经尝试过了,但无法使用 B[x2][y1] 键,它们破坏了一切。目前只有我制作的功能(并在下面发布)有所帮助。无论如何,谢谢你的回答。
  • 对不起,我没有关注这些深嵌套B[x2][y1]的案例!
猜你喜欢
  • 2022-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-24
  • 1970-01-01
  • 2015-09-07
  • 2021-07-15
  • 2013-11-22
相关资源
最近更新 更多