【问题标题】:PHP JSON object nested loop data syntaxPHP JSON 对象嵌套循环数据语法
【发布时间】:2013-10-02 23:01:33
【问题描述】:

我正在尝试遍历一些 JSON 数据并提取特定值。这是 JSON 数据和部分工作的代码。

$jsondata = '
[
  {
  "id" : "421356",
  "trip_update" : {
    "trip" : {
      "trip_id" : "421356",
      "start_time" : "12:05:00",
      "start_date" : "20130926",
      "route_id" : "15"
    },
    "stop_time_update" : {
       "stop_sequence" :70,
      "departure" : {
        "delay" : 240,
        "time" : 1380215057
      },
      "stop_id" : "6090"
    },
    "stop_time_update" : {
       "stop_sequence" :71,
      "departure" : {
        "delay" : 240,
        "time" : 1380215075
      },
      "stop_id" : "6095"
    }
  }
}]';
$result = json_decode($jsondata);

foreach($result as $value) {
  echo "trip_id: ".$value->trip_update->trip->trip_id;
  if (gettype($value->trip_update ) == "object") {
    foreach($value->trip_update as $item) {
       echo " - stop_sequence: ".$item->stop_sequence;
    }
  }
}

我可以得到'trip_update->trip'下的第一级数据。但在“trip_update”中也可以有任意数量的“stop_time_update”数据。由于此数据与 trip_update 数据相关,因此我需要遍历它并关联它。

最终目标是将此数据保存到数据库(代码中未显示),因此为清楚起见,这将是我想在此示例中保存的简化的 2 行数据库数据:

trip_id,stop_sequence
421356,70
421356,71

源数据中可以有任意数量的 stop_sequence。

这里是代码的交互式链接,供您编辑或弄乱: http://sandbox.onlinephpfunctions.com/code/f21ca8928da7de3e9fb351edb075d0a446906937

【问题讨论】:

  • 尝试JSONlint,虽然它是有效的JSON,但stop_time_update 的第二次出现被删除(或者更确切地说,如果被第二次覆盖,则第一次出现),它是对象属性并且不能被定义两次。它应该是一个包含两个对象的数组
  • 谢谢,它验证了。
  • 我知道它是有效的,正如我在评论中提到的那样。关键是,它的结构很糟糕,你应该向这个 JSON 的提供者提及它。
  • 它可能会验证,但您没有围绕重复元素的正确数组结构[]。因此,您在json_decode() 步骤上丢失了数据。

标签: php json object for-loop


【解决方案1】:

如果您编写自己的解析器或使用带有回调的流解析器,您可能会得到更好的结果。这是一个PHP implementation 的这样一个与回调一起工作的解析器。因此,解析器不会将整个 JSON 数据读取到内存中,而是会以块的形式读取数据,并在新对象启动或读取属性等时通知您的“侦听器类”。通过这样做,您应该获得单独的回调事件对于每个 stop_time_update 属性,而不是解析数组中的一个值。

与SAX 的 XML 非常相似。

【讨论】:

  • 嘿,这是一个非常有用的解析器。我认为它会起作用,也许我以后会使用它。但目前 Erick 的解决方案有效。
【解决方案2】:

嗨,也许你可以改名字。

function next_update($coincidencias){
$replace=$coincidencias[0].$GLOBALS["json_stop_time_update"]++;
return $replace;
}
$result= preg_replace_callback("/stop_time_update/","next_update",$jsondata);
$result = json_decode($result);

【讨论】:

  • 天哪,这很有帮助。我能够重命名所有这些,然后遍历它们并从新对象中提取数据。好的。这绝对是一种解决方案 - 修复错误的 JSON 数据。在我标记之前让我看看其他人。
【解决方案3】:

你应该修改你的 JSON - 你有多个同名的键,尝试做 print_r($result) 看看我在说什么 - PHP 将一次又一次地覆盖“stop_time_update”键,你将能够访问只有最后一个条目。相反,您应该像这样组织您的 JSON:

[
  {
  "id" : "421356",
  "trip_update" : {
    "trip" : {
      "trip_id" : "421356",
      "start_time" : "12:05:00",
      "start_date" : "20130926",
      "route_id" : "15"
    },
    "stop_time_update" : [{
       "stop_sequence" :70,
      "departure" : {
        "delay" : 240,
        "time" : 1380215057
      },
      "stop_id" : "6090"
    }, {
       "stop_sequence" :71,
      "departure" : {
        "delay" : 240,
        "time" : 1380215075
      },
      "stop_id" : "6095"
    }]
  }
}]

那么您将能够像这样遍历您的数据:

foreach($result[0]->trip_update->stop_time_update as $update)
{
     $time = $update->departure->time;
     ...
}

如果您无法更改数据结构,那么可能对您有所帮助的是一个 PULL 解析器——它不会返回已解析的数据结构,但允许您改用数据流——这样您就可以遍历每个节点。我设法找到的唯一一个是 PHP 的扩展:

https://github.com/shevron/ext-jsonreader

检查使用部分。

【讨论】:

  • 谢谢,但我无法控制 JSON。它来自外部来源。我想我可以做一些正则表达式替换,以一种方式更改 stop_time_update 的第一个实例,并以另一种方式在同一个 trip_update 中更改后续实例。看起来它可能不起作用,但如果你能举出一个例子,我可以用真实的文件试试。不过我希望有另一种方式。
  • 我明白你的意思。 print_r($result) 表示对象中只保存了最后一次 stop_time_update 数据。
  • 这正是我的观点——如果您的 JSON 包含重复的键,您将只能访问最后提供的值;我不知道有一种 JSON 解析方法会以不同方式处理这种情况
  • 是的,你是对的。由于键重复,我必须调整 JSON 以使其正确解析。
【解决方案4】:

此JSON 响应无效,因为它包含重复的键,但JSON 没有allow duplicate keys。

您应该联系您尝试请求此响应的服务。

如果您有一个有效的JSON 响应,那么您可以使用返回对象或数组的json_decode 函数对其进行解码(取决于第二个参数);

您不能为此使用JSON parser,因为由于相同的键,它总是会覆盖第一个元素。唯一合适的解决方案是要求创建该“JSON”的人修复他的代码以使用数组或具有唯一键的对象。

另一种选择是编写自己的解码器函数来解析它

【讨论】:

  • 感谢您的回答。编写解析会起作用,或者使用现有的解析。因为这是一个技术演示,所以我使用了 Erick 的解决方案,因为它实施起来更快。
猜你喜欢
  • 2019-01-29
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-23
  • 2021-04-10
相关资源
最近更新 更多