【问题标题】:Parsing nested JSON objects with duplicate keys (PHP or JS)使用重复键(PHP 或 JS)解析嵌套的 JSON 对象
【发布时间】:2016-12-23 20:15:48
【问题描述】:

我正在构建一个应用程序,该应用程序基于我从 API 获取的数据,该 API 格式类似于 json_encode() 函数的响应。现在,我不知道(我知道这是可能的)该 API 不时返回重复键的方式。由于修复重复键不是我的站点,我必须找到一个解决方案,如何将此响应解析为包含发送给我的所有数据的可用数组。 我想通过在其键中添加“x01”、“x02”、“x03”...来重命名重复键。 到目前为止,我已经找到了一种可以提供帮助的解决方案(here),但我觉得它只适用于更简单的数组——我处理的是嵌套数组。 因此,这是一个演示 API 响应:

{"boss":"mike",
    "employees":{
       "Josh":{
           "active":"1",
           "hours":"12",
           "name":"Josh"},
       "Josh":{
           "active":"1",
           "hours":"3",
           "name":"Josh"}
    }
}

因此,如您所见,几乎整个“Josh”键都是重复的(“小时”子键除外)。尽管这看起来像一个错误,但这两个值对我来说都很重要。 所以,这是我想要得到的数组:

array (
  "boss" => "mike",
  "employees" = array (
    "x01Josh" = array ("active" => "1", "hours" => "12", "name" => "Josh")
    "x02Josh" = array ("active" => "1", "hours" => "3", "name" => "Josh")
  )
)

我有一个想法,甚至一次只检查一个单词,检查它是否是字符串、双引号、逗号或任何花括号,并相应地构建一个函数。我认为这将需要很长且效率低下的代码(处理速度很慢)。

由于我是 RegEx 的新手,并且我也没有找到解决方案(我确信它存在,但我没有设法找到它),所以我向您寻求帮助。

我打算在 JavaScript/jQuery 或 PHP 中解析它(使用另一个 JSON 请求)。 提前致谢。

更新我忘了提 - 我这样做的原因是因为第二个键覆盖了第一个键(重复)。此外,我无法更改 API(这不是我网站的 API)。我已经要求他们对这些问题进行一些更改,但与此同时,我必须从我这边去做。

【问题讨论】:

  • 在 javascript 中,一个重复的键会覆盖第一个键。在严格模式下,它会返回一个错误。
  • 完全正确 - 这就是为什么我需要以某种方式解析它,以便它可以在没有错误或覆盖的情况下使用。
  • 这些重复的键是否完全排在后面?
  • 是的。另外,有时只有一个“josh”实例,有时是两个(因此重复)。
  • 尽你所能找出数据不可预测的原因。看起来你是在根据数据的不可靠性做补丁,看起来是在浪费时间。此外,如果您无法控制外部 API。

标签: javascript php arrays json regex


【解决方案1】:

使用String.replaceString.matchArray.filterArray.shift函数的JS解决方案:

var jsonData = '{"boss":"mike","employees":{"Josh":{"active":"1","hours":"12","name":"Josh"},"Josh":{"active":"1","hours":"3","name":"Josh"}}}',
    re = /\"(\w+?)(?=\":\{)/g, names = {}, dups;

jsonData.match(re).forEach(function(v){
    v = v.replace(/\"/, "");
    (!names[v])? names[v] = 1 : names[v]++;
});

dups = Object.keys(names).filter(function(k) { return names[k] > 1; }); // getting duplicated keys
dups.forEach(function (k) {
    var count = names[k], i;
    names[k] = [];

    for (i = 0; i < count; i++) {
        names[k].push("x0" + (i+1));
    }
});

jsonData = jsonData.replace(re, function (p1) { // replacing duplicate keys
    p1 = p1.substr(1);
    if (dups.indexOf(p1) !== -1) {
        return '"' + names[p1].shift() + p1;
    } else {
        return '"' + p1;
    }
});

console.log(JSON.parse(jsonData));

【讨论】:

  • 它就像一个魅力,你所写的一切都完全按照给定的字符串显示。但是,当我尝试使用真正的 API 字符串时,它不起作用,因为密钥在名称中包含一个句点(“agapetos.main”)。当我尝试“agapetos”时,一切都很好。是否可以将其添加到不被句号抛出的函数中?
  • 我的真实(不是演示,简化版)看起来像这样:{"username":"agapetos","workers":{"agapetos.main":{"alive":"1" ,"hashrate":"8351","username":"agapetos.main"},"agapetos.main":{"alive":"1","hashrate":"22668","username":"agapetos.主"}}}
  • @agapetos,好的,我会在健身房之后做(如果你在那之前没有任何其他解决方案)
  • 所以,我用/\"([\w\.]+?)(?=\":\{)/g 代替了/\"(\w+?)(?=\":\{)/g,这样就成功了(现在它也接受键中的句点)。感谢您提供出色的代码 :)
  • @agapetos,不客气。我很高兴你猜到了那个“把戏”
【解决方案2】:

不能更改 API 吗?您发布的内容不是 JSON。它返回一个带有重复键的映射,而不是一个对象数组。

如果您需要“用你所得到的东西工作”。然后您可能需要考虑构建自己的解析器。对嵌套结构使用正则表达式并不理想。

【讨论】:

  • 我也发现他们(拥有 API 的网站的所有者)没有使用 json_encode() 对其进行编码,而是以某种方式自行构建。正如你所说,我需要用我得到的东西工作。这正是本主题所要讨论的——如何为这些情况制作一个好的解析器。我一直在努力通过使用我熟悉的 PHP 中的函数分析单词来制作一个。但是,由于我在正则表达式方面仍然不是那么好,所以我可能需要几天时间才能想出一个好的解析器,或者需要几个小时才能想出一个巨大的低效代码。
  • this solution 帮忙吗?
  • @agapetos 我可能会考虑构建自己的状态机来解析他们的“JSON”字符串。检查它是否在解析键或值并在 PHP 中构建等效项。加上注释,员工的值需要是数组而不是地图。
  • @nolan 所以,如果我理解正确的话,它会产生类似这样的结果:array ( "boss" =&gt; "mike", "employees" = array ( array ("active" =&gt; "1", "hours" =&gt; "12", "name" =&gt; "Josh") array ("active" =&gt; "1", "hours" =&gt; "3", "name" =&gt; "Josh") ) ) 如果是这样,那会做得很好。我现在就测试一下:)谢谢
  • 嗯,我试过了。它可能适用于简单的数组,但不适用于我的数组。这是它从我那里返回的内容:link
猜你喜欢
  • 1970-01-01
  • 2019-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多