這是另一個'走樹'問題。 JSON streaming parser讀取源文件並開始構建'樹'。它通過收集「元素」並將它們存儲在內存中來實現這一點。爲了使我們能夠處理每個條目,它在方便的時候「發佈事件」。這意味着它會根據需要調用你的函數傳遞有用的值。 '樹事件' 的
的例子是:
那麼,我們如何確定一個'完整的事件'?
輸入文件由一個數組組成,其中每個條目是JSON的「obbject」。每個對象由組成'對象'數據的'子條目'組成。
現在,當我們遍歷'樹'構建它時,我們的代碼將在如上所示的各個點處被調用。特別是當對象和數組的「開始」和「結束」時。我們需要收集「外部對象」的所有數據。
我們如何識別?隨着處理過程的進行,我們記錄下「樹」中的位置。我們通過跟蹤樹中「嵌套」的深度來做到這一點。因此,'水平'。一個對象的'開始''嵌套'一個層次,一個對象的'結束''突破'一個層次。
我們感興趣的對象是'1級'。
提供的代碼: 1)跟蹤'等級',並在達到'等級1'的對象末尾時調用我們的函數。 2)從'level 1'處的對象的開始累積適當結構中的數據。
要求:
1)稱之爲「可贖回」程序時,有一個「完整的事件」,可以進行處理。
假設:
處理:
- 解析文件
- 每當當前事件是 '完整'
- 執行 '的processEvent' 調用與訪問當前事件。
源代碼:
代碼:index.php文件
<?php // https://stackoverflow.com/questions/31079129/how-to-handle-nested-objects-in-processing-a-json-stream
require_once __DIR__ .'/vendor/jsonstreamingparser/src/JsonStreamingParser/Parser.php';
require_once __DIR__ .'/vendor/jsonstreamingparser/src/JsonStreamingParser/Listener/IdleListener.php';
require_once __DIR__ .'/Q31079129Listener.php';
/**
* The input file consists of a JSON array of 'Events'.
*
* The important point is that when the file is being 'parsed' the 'listener' is
* 'walking' the tree.
*
* Therefore
* 1) Each 'Event' is at 'level 1' in the tree.
*
* Event Level Changes:
* Start: level will go from 1 => 2
* End: level will go from 2 => 1 !!!!
*
* Actions:
* The 'processEvent' function will be called when the
* 'Event Level' changes to 2 from 1.
*
*/
define('JSON_FILE', __DIR__. '/Q31079129.json');
/**
* This is called when one 'Event' is complete
*
* @param type $listener
*/
function processEvent($listener) {
echo '<pre>', '+++++++++++++++';
print_r($listener->get_event());
echo '</pre>';
}
// ----------------------------------------------------------------------
// the 'Listener'
$listener = new Q31079129Listener();
// setup the 'Event' Listener that will be called with each complete 'Event'
$listener->whenLevelAction = 'processEvent';
// process the input stream
$stream = fopen(JSON_FILE, 'r');
try {
$parser = new JsonStreamingParser_Parser($stream, $listener);
$parser->parse();
}
catch (Exception $e) {
fclose($stream);
throw $e;
}
fclose($stream);
exit;
代碼:Q31079129Listener.php
<?php // // https://stackoverflow.com/questions/31079129/how-to-handle-nested-objects-in-processing-a-json-stream
/**
* This is the supplied example modified:
*
* 1) Record the current 'depth' of 'nesting' in the current object being parsed.
*/
class Q31079129Listener extends JsonStreamingParser\Listener\IdleListener {
public $whenLevelAction = null;
protected $event;
protected $prevLevel;
protected $level;
private $_stack;
private $_keys;
public function get_event() {
return $this->event;
}
public function get_prevLevel() {
return $this->prevLevel;
}
public function get_level() {
return $this->prevLevel;
}
public function start_document() {
$this->prevLevel = 0;
$this->level = 0;
$this->_stack = array();
$this->_keys = array();
// echo '<br />start of document';
}
public function end_document() {
// echo '<br />end of document';
}
public function start_object() {
$this->prevLevel = $this->level;
$this->level++;
$this->_start_complex_value('object');
}
public function end_object() {
$this->prevLevel = $this->level;
$this->level--;
$this->_end_complex_value();
}
public function start_array() {
$this->prevLevel = $this->level;
$this->level++;
$this->_start_complex_value('array');
}
public function end_array() {
$this->prevLevel = $this->level;
$this->level--;
$this->_end_complex_value();
}
public function key($key) {
$this->_keys[] = $key;
}
public function value($value) {
$this->_insert_value($value);
}
private function _start_complex_value($type) {
// We keep a stack of complex values (i.e. arrays and objects) as we build them,
// tagged with the type that they are so we know how to add new values.
$current_item = array('type' => $type, 'value' => array());
$this->_stack[] = $current_item;
}
private function _end_complex_value() {
$obj = array_pop($this->_stack);
// If the value stack is now at level 1 from level 2,
// we're done parsing the current complete event, so we can
// move the result into place so that get_event() can return it. Otherwise, we
// associate the value
// var_dump(__FILE__.__LINE__, $this->prevLevel, $this->level, $obj);
if ($this->prevLevel == 2 && $this->level == 1) {
if (!is_null($this->whenLevelAction)) {
$this->event = $obj['value'];
call_user_func($this->whenLevelAction, $this);
$this->event = null;
}
}
else {
$this->_insert_value($obj['value']);
}
}
// Inserts the given value into the top value on the stack in the appropriate way,
// based on whether that value is an array or an object.
private function _insert_value($value) {
// Grab the top item from the stack that we're currently parsing.
$current_item = array_pop($this->_stack);
// Examine the current item, and then:
// - if it's an object, associate the newly-parsed value with the most recent key
// - if it's an array, push the newly-parsed value to the array
if ($current_item['type'] === 'object') {
$current_item['value'][array_pop($this->_keys)] = $value;
} else {
$current_item['value'][] = $value;
}
// Replace the current item on the stack.
$this->_stack[] = $current_item;
}
}
的解決方案將讀取數據流的兩倍。您第一次閱讀所有強制性屬性。第二次處理與會者併發出邀請(這不是很優雅,但只有流,並且您控制了內存限制) – Mat
嗯,我對JSON結構有一些控制權。我擔心的是,生成JSON的客戶端可能不會像對象屬性的排序那樣控制事物......所以當他們告訴他們的代碼將對象轉換爲JSON時,對象屬性順序可能不可控。 –
iam_decoder - 感謝您的編輯! –