You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从带路径的键值对字典重建嵌套JSON?代码问题排查

问题:从带路径标记的键值对重建JSON结构

背景

需要从带路径标记的键值对字典重建类JSON结构:

  • 键代表叶子节点的完整路径,值为对应位置的数据集;
  • 键中的|TRUE|/|FALSE|标记该节点是否为数组类型。

输入的键值对字典

{
  FirstName: [ 'Penelope' ],
  LastName: [ 'Veum' ],
  BusinessPartnerCategory: [ '1' ],
  SearchTerm1: [ 'DZBANK456' ],
  CorrespondenceLanguage: [ 'EN' ],
  'to_Customer|TRUE|.InternationalLocationNumber1': [ '0' ],
  'to_Customer|TRUE|.CustomerAccountGroup': [ 'CUST' ],
  'to_Customer|TRUE|.to_CustomerSalesArea|FALSE|.results|TRUE|.SalesOrganization': [ '1710' ],
  'to_Customer|TRUE|.to_CustomerSalesArea|FALSE|.results|TRUE|.DistributionChannel': [ '10' ],
  'to_Customer|TRUE|.to_CustomerSalesArea|FALSE|.results|TRUE|.Division': [ '00' ],
  'to_Customer|TRUE|.to_CustomerSalesArea|FALSE|.results|TRUE|.Currency': [ 'EUR' ],
  'to_Customer|TRUE|.to_CustomerSalesArea|FALSE|.results|TRUE|.ItemOrderProbabilityInPercent': [ '100' ],
  'to_Customer|TRUE|.to_CustomerSalesArea|FALSE|.results|TRUE|.CompleteDeliveryIsDefined': [ false ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.Country': [ 'US' ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.CityName': [ 'Atlanta' ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.Region': [ 'GA' ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.PostalCode': [ '30303' ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.StreetName': [ '543 Peachtree Street' ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.to_EmailAddress|FALSE|.results|TRUE|.IsDefaultEmailAddress': [ true ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.to_EmailAddress|FALSE|.results|TRUE|.EmailAddress': [ '{{FirstName}}.{{LastName}}@gmail.com' ],
  'to_BusinessPartnerAddress|FALSE|.results|TRUE|.to_EmailAddress|FALSE|.results|TRUE|.AddressCommunicationRemarkText': [ 'the' ],
  'to_BusinessPartnerRole|FALSE|.results|TRUE|.BusinessPartnerRole': [ 'FLCU00' ]
}

预期输出

{
    "FirstName": "Jarrell",
    "LastName": "Bode",
    "BusinessPartnerCategory": "1",
    "SearchTerm1": "DZBANK456",
    "CorrespondenceLanguage": "EN",
    "to_BusinessPartnerRole": {
        "results": [
            {
                "BusinessPartnerRole": "FLCU00"
            }
        ]
    },
    "to_BusinessPartnerAddress": {
        "results": [
            {
                "to_EmailAddress": {
                    "results": [
                        {
                            "IsDefaultEmailAddress": true,
                            "EmailAddress": "Jarrell.Bode@gmail.com",
                            "AddressCommunicationRemarkText": "whoa"
                        }
                    ]
                },
                "Country": "US",
                "CityName": "Atlanta",
                "Region": "GA",
                "PostalCode": "30303",
                "StreetName": "543 Peachtree Street"
            }
        ]
    },
    "to_Customer": [
        {
            "InternationalLocationNumber1": "0",
            "to_CustomerSalesArea": {
                "results": [
                    {
                        "SalesOrganization": "1710",
                        "DistributionChannel": "10",
                        "Division": "00",
                        "Currency": "USD",
                        "ItemOrderProbabilityInPercent": "100",
                        "CompleteDeliveryIsDefined": false
                    }
                ]
            },
            "CustomerAccountGroup": "CUST"
        }
    ]
}

现有代码

const final_result = [];
for (let index = 0; index < quantity; index++) {
  let response_cpy = Object.assign({}, response_new);
  for (const [path, data] of Object.entries(pathDataDict)) {
    const pathSplit = path.split(".");
    pathSplit.reduce(function (response: any, incompleteKey: any) {
      const keySplit = incompleteKey.split("|");
      const actualKey = keySplit[0];
      if (actualKey === pathSplit[pathSplit.length - 1]) {
        if (
          typeof response === "object" &&
          !Array.isArray(response) &&
          response !== null
        ) {
          return (response[actualKey] = (data as any)[index]);
        } else {
          return (response[0][actualKey] = (data as any)[index]);
        }
      } else {
        return (
          response[actualKey] ||
          (keySplit.length > 1 && keySplit[1] === "TRUE"
            ? (response[actualKey] = [{}])
            : (response[actualKey] = {}))
        );
      }
    }, response_cpy);
  }
  final_result.push(response_cpy);
}

现有代码问题:生成猴子补丁属性,非叶子节点丢失,数组出现异常属性。


代码问题分析

  1. reduce回调返回值错误:处理叶子节点时,返回的是赋值后的叶子值而非当前父节点,导致后续同一父节点的其他叶子路径处理时,上下文变成了叶子值,进而在基础类型上添加属性,出现猴子补丁。
  2. 叶子节点判断逻辑错误:用actualKey === pathSplit[pathSplit.length - 1]判断是否为叶子节点,会混淆同名节点的层级,无法准确区分当前处理的片段是否为路径的最后一级。
  3. 数组节点处理不严谨:直接取数组的response[0]但未检查数组是否为空,且切换上下文时未正确定位到数组内部的对象,导致属性错误挂载到数组本身而非数组内的元素。

修复后的代码实现

function buildJsonStructure(pathDataDict: Record<string, any[]>, quantity: number): any[] {
  const finalResult: any[] = [];

  for (let index = 0; index < quantity; index++) {
    const result: any = {};

    for (const [path, dataList] of Object.entries(pathDataDict)) {
      const pathSegments = path.split(".");
      let currentContext = result;

      for (let i = 0; i < pathSegments.length; i++) {
        const segment = pathSegments[i];
        const [key, isArrayStr] = segment.split("|");
        const isArray = isArrayStr === "TRUE";
        const isLastSegment = i === pathSegments.length - 1;

        if (isLastSegment) {
          // 处理叶子节点:赋值对应数据
          if (Array.isArray(currentContext)) {
            // 数组上下文确保有元素可赋值
            if (currentContext.length === 0) currentContext.push({});
            currentContext[0][key] = dataList[index];
          } else {
            currentContext[key] = dataList[index];
          }
        } else {
          // 处理非叶子节点:确保结构存在并切换上下文
          if (!currentContext[key]) {
            currentContext[key] = isArray ? [{}] : {};
          }
          // 切换到子节点上下文:数组取第一个元素,对象直接取节点
          currentContext = Array.isArray(currentContext[key]) 
            ? currentContext[key][0] 
            : currentContext[key];
        }
      }
    }

    finalResult.push(result);
  }

  return finalResult;
}

// 使用示例
// const output = buildJsonStructure(pathDataDict, quantity);
// console.log(JSON.stringify(output, null, 2));

修复说明

  1. 替换reduce为普通循环:用for循环遍历路径片段,直观控制上下文切换,避免reduce返回值导致的上下文混乱。
  2. 准确判断叶子节点:通过迭代索引i === pathSegments.length - 1判断是否为路径最后一级,彻底解决同名节点的层级混淆问题。
  3. 严谨维护数组结构:
    • 创建数组节点时直接初始化[{}],确保内部有可承载属性的空对象;
    • 处理叶子节点时先检查数组是否为空,为空则添加元素再赋值。
  4. 正确切换上下文:每次处理完非叶子节点后,将上下文切换到节点内部(数组取第一个元素,对象直接取节点),确保后续路径在正确层级处理。

内容的提问来源于stack exchange,提问作者CodingAddict

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:24:54