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

Laravel中带通配符的数组还原与JSON Schema映射问题

解决Laravel中JSON Schema映射的索引还原问题

问题根源分析

你当前的实现核心问题在于:将数组扁平化后用正则把数字索引替换成*,但Laravel的data_fill无法将*识别为动态索引,而是直接当作字面量键名,导致最终结果出现*键,且多元素数组(如pedidos)的内容被覆盖,未映射的字段(如email)被孤立。

修复后的实现代码

我们需要保留原索引数字,通过正则匹配映射规则,将通配符*替换为对应的捕获组,生成带正确索引的键路径,再用data_set设置值:

use Illuminate\Support\Arr;

$payload = [
    [
        "identificador" => 1,
        "nome_completo" => "John Doe",
        "email" => "j@email.com",
        "empresa" => [
            "razao_social" => "ABC Company",
            "endereco" => "123 Main St"
        ],
        "pedidos" => [
            [
                "SKU" => 1,
                "descricao" => "Shoes",
                "qtd" => 2
            ],
            [
                "SKU" => 2,
                "descricao" => "Shirt",
                "qtd" => 1
            ]
        ]
    ]
];

$mappingConfig = [
    "*.identificador" => "*.id",
    "*.nome_completo" => "*.name",
    "*.empresa.razao_social" => "*.company.name",
    "*.empresa.endereco" => "*.company.address",
    "*.pedidos.*.SKU" => "*.orders.*.id",
    "*.pedidos.*.descricao" => "*.orders.*.product",
    "*.pedidos.*.qtd" => "*.orders.*.quantity",
];

// 将映射规则转换为正则+替换模板
$regexMappings = [];
foreach ($mappingConfig as $pattern => $replacement) {
    // 把*转为捕获数字的正则组
    $regexPattern = preg_replace('/\*/', '(\d+)', $pattern);
    $regexPattern = '/^' . str_replace('.', '\.', $regexPattern) . '$/';
    
    // 把替换模板中的*转为捕获组占位符
    $replaceTemplate = preg_replace('/\*/', '$$$1', $replacement);
    
    $regexMappings[] = [
        'regex' => $regexPattern,
        'replace' => $replaceTemplate,
    ];
}

$dottedPayload = Arr::dot($payload);
$transformedPayload = [];

foreach ($dottedPayload as $key => $value) {
    $newKey = $key; // 默认保留原键
    
    // 匹配映射规则
    foreach ($regexMappings as $mapping) {
        if (preg_match($mapping['regex'], $key, $matches)) {
            array_shift($matches); // 移除完整匹配的字符串,保留捕获的索引
            // 替换捕获组占位符为实际索引
            $newKey = preg_replace_callback('/\$(\d+)/', function($match) use ($matches) {
                return $matches[$match[1]-1];
            }, $mapping['replace']);
            break;
        }
    }
    
    // 用data_set替代data_fill,确保值被正确设置到路径
    data_set($transformedPayload, $newKey, $value);
}

// 输出结果与预期一致
dd($transformedPayload);

优化方案:递归遍历处理(无需扁平化)

对于复杂嵌套结构,递归遍历数组可以更直观地控制转换逻辑,避免扁平化带来的路径处理问题:

function transformArray($array, $mappingConfig, $currentPath = '') {
    $result = [];
    
    foreach ($array as $key => $value) {
        $fullPath = $currentPath ? "{$currentPath}.{$key}" : $key;
        $mappedPath = $fullPath;
        
        // 匹配映射规则
        foreach ($mappingConfig as $pattern => $replacement) {
            $regexPattern = preg_replace('/\*/', '(\d+)', $pattern);
            $regexPattern = '/^' . str_replace('.', '\.', $regexPattern) . '$/';
            
            if (preg_match($regexPattern, $fullPath, $matches)) {
                array_shift($matches);
                $mappedPath = preg_replace_callback('/\$(\d+)/', function($match) use ($matches) {
                    return $matches[$match[1]-1];
                }, preg_replace('/\*/', '$$$1', $replacement));
                break;
            }
        }
        
        // 拆分目标路径,设置值或递归处理子数组
        $pathParts = explode('.', $mappedPath);
        $targetKey = array_pop($pathParts);
        $targetParent = implode('.', $pathParts);
        
        if (is_array($value)) {
            $childResult = transformArray($value, $mappingConfig, $fullPath);
            $targetParent ? data_set($result, "{$targetParent}.{$targetKey}", $childResult) : ($result[$targetKey] = $childResult);
        } else {
            $targetParent ? data_set($result, "{$targetParent}.{$targetKey}", $value) : ($result[$targetKey] = $value);
        }
    }
    
    return $result;
}

// 使用方式
$transformedPayload = transformArray($payload, $mappingConfig);
dd($transformedPayload);

关键优化点

  1. 保留原索引:通过正则捕获原路径中的数字索引,替换映射规则中的*,生成带正确索引的目标路径。
  2. 使用data_set:替代data_fill,确保每个值都被精准设置到目标路径,避免多元素数组的覆盖问题。
  3. 递归遍历:对于复杂嵌套结构,递归处理无需扁平化数组,逻辑更清晰,性能更优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 16:07:03