Pretty-Printing JSON с PHP

Я создаю PHP-скрипт, который передает данные JSON в другой скрипт. Мой скрипт строит данные в большой ассоциативный массив, а затем выводит данные с помощью json_encode . Вот пример скрипта:

 $data = array('a' => 'apple', 'b' => 'banana', 'c' => 'catnip'); header('Content-type: text/javascript'); echo json_encode($data); 

Вышеприведенный код дает следующий результат:

 {"a":"apple","b":"banana","c":"catnip"} 

Это здорово, если у вас есть небольшой объем данных, но я бы предпочел что-то в этом направлении:

 { "a": "apple", "b": "banana", "c": "catnip" } 

Есть ли способ сделать это на PHP без уродливого взлома? Похоже, кто-то в Facebook понял это.

    PHP 5.4 предлагает параметр JSON_PRETTY_PRINT для использования с вызовом json_encode() .

    http://php.net/manual/en/function.json-encode.php

     <?php ... $json_string = json_encode($data, JSON_PRETTY_PRINT); 

    Эта функция примет строку JSON и ее отступы, которые очень читаемы. Он также должен быть сходящимся,

     prettyPrint( $json ) === prettyPrint( prettyPrint( $json ) ) 

    вход

     {"key1":[1,2,3],"key2":"value"} 

    Вывод

     { "key1": [ 1, 2, 3 ], "key2": "value" } 

    Код

     function prettyPrint( $json ) { $result = ''; $level = 0; $in_quotes = false; $in_escape = false; $ends_line_level = NULL; $json_length = strlen( $json ); for( $i = 0; $i < $json_length; $i++ ) { $char = $json[$i]; $new_line_level = NULL; $post = ""; if( $ends_line_level !== NULL ) { $new_line_level = $ends_line_level; $ends_line_level = NULL; } if ( $in_escape ) { $in_escape = false; } else if( $char === '"' ) { $in_quotes = !$in_quotes; } else if( ! $in_quotes ) { switch( $char ) { case '}': case ']': $level--; $ends_line_level = NULL; $new_line_level = $level; break; case '{': case '[': $level++; case ',': $ends_line_level = $level; break; case ':': $post = " "; break; case " ": case "\t": case "\n": case "\r": $char = ""; $ends_line_level = $new_line_level; $new_line_level = NULL; break; } } else if ( $char === '\\' ) { $in_escape = true; } if( $new_line_level !== NULL ) { $result .= "\n".str_repeat( "\t", $new_line_level ); } $result .= $char.$post; } return $result; } 

    Я была такая же проблема.

    Во всяком случае, я просто использовал код форматирования json здесь:

    http://recursive-design.com/blog/2008/03/11/format-json-with-php/

    Хорошо работает для того, для чего мне это нужно.

    И более поддерживаемая версия: https://github.com/GerHobbelt/nicejson-php

    Многие пользователи предложили использовать

     echo json_encode($results, JSON_PRETTY_PRINT); 

    Это абсолютно правильно. Но этого недостаточно, браузер должен понимать тип данных, вы можете указать заголовок непосредственно перед тем, как вернуть данные обратно пользователю.

     header('Content-Type: application/json'); 

    Это приведет к хорошо отформатированному результату.

    Или, если вам нравятся расширения, вы можете использовать JSONView для Chrome.

    Если вы используете firefox, установите JSONovich . На самом деле это не PHP-решение, которое я знаю, но оно делает трюк для целей разработки / отладки.

    Я взял код из Composer: https://github.com/composer/composer/blob/master/src/Composer/Json/JsonFile.php и nicejson: https://github.com/GerHobbelt/nicejson-php/blob /master/nicejson.php Код композитора хорош, потому что он плавно обновляется с 5.3 до 5.4, но он только кодирует объект, тогда как nicejson принимает строки json, поэтому я объединил их. Код может использоваться для форматирования json string и / или кодирования объектов, в настоящее время я использую его в модуле Drupal.

     if (!defined('JSON_UNESCAPED_SLASHES')) define('JSON_UNESCAPED_SLASHES', 64); if (!defined('JSON_PRETTY_PRINT')) define('JSON_PRETTY_PRINT', 128); if (!defined('JSON_UNESCAPED_UNICODE')) define('JSON_UNESCAPED_UNICODE', 256); function _json_encode($data, $options = 448) { if (version_compare(PHP_VERSION, '5.4', '>=')) { return json_encode($data, $options); } return _json_format(json_encode($data), $options); } function _pretty_print_json($json) { return _json_format($json, JSON_PRETTY_PRINT); } function _json_format($json, $options = 448) { $prettyPrint = (bool) ($options & JSON_PRETTY_PRINT); $unescapeUnicode = (bool) ($options & JSON_UNESCAPED_UNICODE); $unescapeSlashes = (bool) ($options & JSON_UNESCAPED_SLASHES); if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) { return $json; } $result = ''; $pos = 0; $strLen = strlen($json); $indentStr = ' '; $newLine = "\n"; $outOfQuotes = true; $buffer = ''; $noescape = true; for ($i = 0; $i < $strLen; $i++) { // Grab the next character in the string $char = substr($json, $i, 1); // Are we inside a quoted string? if ('"' === $char && $noescape) { $outOfQuotes = !$outOfQuotes; } if (!$outOfQuotes) { $buffer .= $char; $noescape = '\\' === $char ? !$noescape : true; continue; } elseif ('' !== $buffer) { if ($unescapeSlashes) { $buffer = str_replace('\\/', '/', $buffer); } if ($unescapeUnicode && function_exists('mb_convert_encoding')) { // http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha $buffer = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function ($match) { return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE'); }, $buffer); } $result .= $buffer . $char; $buffer = ''; continue; } elseif(false !== strpos(" \t\r\n", $char)) { continue; } if (':' === $char) { // Add a space after the : character $char .= ' '; } elseif (('}' === $char || ']' === $char)) { $pos--; $prevChar = substr($json, $i - 1, 1); if ('{' !== $prevChar && '[' !== $prevChar) { // If this character is the end of an element, // output a new line and indent the next line $result .= $newLine; for ($j = 0; $j < $pos; $j++) { $result .= $indentStr; } } else { // Collapse empty {} and [] $result = rtrim($result) . "\n\n" . $indentStr; } } $result .= $char; // If the last character was the beginning of an element, // output a new line and indent the next line if (',' === $char || '{' === $char || '[' === $char) { $result .= $newLine; if ('{' === $char || '[' === $char) { $pos++; } for ($j = 0; $j < $pos; $j++) { $result .= $indentStr; } } } // If buffer not empty after formating we have an unclosed quote if (strlen($buffer) > 0) { //json is incorrectly formatted $result = false; } return $result; } 

    Я понимаю, что этот вопрос задает вопрос о том, как закодировать ассоциативный массив на строку в формате JSON с довольно отформатированной версией, поэтому это напрямую не отвечает на вопрос, но если у вас есть строка, которая уже находится в формате JSON, вы можете сделать это довольно просто путем декодирования и повторного кодирования (требуется PHP> = 5.4):

     $json = json_encode(json_decode($json), JSON_PRETTY_PRINT); 

    Пример:

     header('Content-Type: application/json'); $json_ugly = '{"a":1,"b":2,"c":3,"d":4,"e":5}'; $json_pretty = json_encode(json_decode($json_ugly), JSON_PRETTY_PRINT); echo $json_pretty; 

    Эти результаты:

     { "a": 1, "b": 2, "c": 3, "d": 4, "e": 5 } 

    Используйте <pre> в сочетании с json_encode() и опцией JSON_PRETTY_PRINT :

     <pre> <?php echo json_encode($dataArray, JSON_PRETTY_PRINT); ?> </pre> 

    Вы можете немного изменить ответ Kendall Hopkins в инструкции switch, чтобы получить красивую и красиво отпечатанную распечатку, передав строку json в следующее:

     function prettyPrint( $json ){ $result = ''; $level = 0; $in_quotes = false; $in_escape = false; $ends_line_level = NULL; $json_length = strlen( $json ); for( $i = 0; $i < $json_length; $i++ ) { $char = $json[$i]; $new_line_level = NULL; $post = ""; if( $ends_line_level !== NULL ) { $new_line_level = $ends_line_level; $ends_line_level = NULL; } if ( $in_escape ) { $in_escape = false; } else if( $char === '"' ) { $in_quotes = !$in_quotes; } else if( ! $in_quotes ) { switch( $char ) { case '}': case ']': $level--; $ends_line_level = NULL; $new_line_level = $level; $char.="<br>"; for($index=0;$index<$level-1;$index++){$char.="-----";} break; case '{': case '[': $level++; $char.="<br>"; for($index=0;$index<$level;$index++){$char.="-----";} break; case ',': $ends_line_level = $level; $char.="<br>"; for($index=0;$index<$level;$index++){$char.="-----";} break; case ':': $post = " "; break; case "\t": case "\n": case "\r": $char = ""; $ends_line_level = $new_line_level; $new_line_level = NULL; break; } } else if ( $char === '\\' ) { $in_escape = true; } if( $new_line_level !== NULL ) { $result .= "\n".str_repeat( "\t", $new_line_level ); } $result .= $char.$post; } echo "RESULTS ARE: <br><br>$result"; return $result; 

    }

    Теперь просто запустите функцию prettyPrint ($ your_json_string); встроенный в ваш php и наслаждаться распечаткой. Если вы по каким-то причинам минималистичны и не любите скобки, вы можете легко избавиться от них, заменив $char.="<br>"; с $char="<br>"; в трех верхних коммутационных шкафах на $ char. Вот что вы получаете за API API Google Maps для города Калгари

     RESULTS ARE: { - - - "results" : [ - - -- - - { - - -- - -- - - "address_components" : [ - - -- - -- - -- - - { - - -- - -- - -- - -- - - "long_name" : "Calgary" - - -- - -- - -- - -- - - "short_name" : "Calgary" - - -- - -- - -- - -- - - "types" : [ - - -- - -- - -- - -- - -- - - "locality" - - -- - -- - -- - -- - -- - - "political" ] - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - - { - - -- - -- - -- - -- - - "long_name" : "Division No. 6" - - -- - -- - -- - -- - - "short_name" : "Division No. 6" - - -- - -- - -- - -- - - "types" : [ - - -- - -- - -- - -- - -- - - "administrative_area_level_2" - - -- - -- - -- - -- - -- - - "political" ] - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - - { - - -- - -- - -- - -- - - "long_name" : "Alberta" - - -- - -- - -- - -- - - "short_name" : "AB" - - -- - -- - -- - -- - - "types" : [ - - -- - -- - -- - -- - -- - - "administrative_area_level_1" - - -- - -- - -- - -- - -- - - "political" ] - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - - { - - -- - -- - -- - -- - - "long_name" : "Canada" - - -- - -- - -- - -- - - "short_name" : "CA" - - -- - -- - -- - -- - - "types" : [ - - -- - -- - -- - -- - -- - - "country" - - -- - -- - -- - -- - -- - - "political" ] - - -- - -- - -- - - } - - -- - -- - - ] - - -- - - - - -- - -- - - "formatted_address" : "Calgary, AB, Canada" - - -- - -- - - "geometry" : { - - -- - -- - -- - - "bounds" : { - - -- - -- - -- - -- - - "northeast" : { - - -- - -- - -- - -- - -- - - "lat" : 51.18383 - - -- - -- - -- - -- - -- - - "lng" : -113.8769511 } - - -- - -- - -- - - - - -- - -- - -- - -- - - "southwest" : { - - -- - -- - -- - -- - -- - - "lat" : 50.84240399999999 - - -- - -- - -- - -- - -- - - "lng" : -114.27136 } - - -- - -- - -- - - } - - -- - -- - - - - -- - -- - -- - - "location" : { - - -- - -- - -- - -- - - "lat" : 51.0486151 - - -- - -- - -- - -- - - "lng" : -114.0708459 } - - -- - -- - - - - -- - -- - -- - - "location_type" : "APPROXIMATE" - - -- - -- - -- - - "viewport" : { - - -- - -- - -- - -- - - "northeast" : { - - -- - -- - -- - -- - -- - - "lat" : 51.18383 - - -- - -- - -- - -- - -- - - "lng" : -113.8769511 } - - -- - -- - -- - - - - -- - -- - -- - -- - - "southwest" : { - - -- - -- - -- - -- - -- - - "lat" : 50.84240399999999 - - -- - -- - -- - -- - -- - - "lng" : -114.27136 } - - -- - -- - -- - - } - - -- - -- - - } - - -- - - - - -- - -- - - "place_id" : "ChIJ1T-EnwNwcVMROrZStrE7bSY" - - -- - -- - - "types" : [ - - -- - -- - -- - - "locality" - - -- - -- - -- - - "political" ] - - -- - - } - - - ] - - - "status" : "OK" } 

    Получите полную цветовую мощность: крошечное решение

    Код:

     $s = '{"access": {"token": {"issued_at": "2008-08-16T14:10:31.309353", "expires": "2008-08-17T14:10:31Z", "id": "MIICQgYJKoZIhvcIegeyJpc3N1ZWRfYXQiOiAi"}, "serviceCatalog": [], "user": {"username": "ajay", "roles_links": [], "id": "16452ca89", "roles": [], "name": "ajay"}}}'; $crl = 0; $ss = false; echo "<pre>"; for($c=0; $c<strlen($s); $c++) { if ( $s[$c] == '}' || $s[$c] == ']' ) { $crl--; echo "\n"; echo str_repeat(' ', ($crl*2)); } if ( $s[$c] == '"' && ($s[$c-1] == ',' || $s[$c-2] == ',') ) { echo "\n"; echo str_repeat(' ', ($crl*2)); } if ( $s[$c] == '"' && !$ss ) { if ( $s[$c-1] == ':' || $s[$c-2] == ':' ) echo '<span style="color:#0000ff;">'; else echo '<span style="color:#ff0000;">'; } echo $s[$c]; if ( $s[$c] == '"' && $ss ) echo '</span>'; if ( $s[$c] == '"' ) $ss = !$ss; if ( $s[$c] == '{' || $s[$c] == '[' ) { $crl++; echo "\n"; echo str_repeat(' ', ($crl*2)); } } echo $s[$c]; 

    Если вы использовали только $json_string = json_encode($data, JSON_PRETTY_PRINT); , вы получите в браузере что-то вроде этого (используя ссылку Facebook из вопроса :)): введите описание изображения здесь

    но если вы использовали расширение chrome, такое как JSONView (даже без опции PHP выше), вы получите более красивое читаемое отладочное решение, в котором вы можете легко свернуть / свернуть каждый отдельный объект JSON следующим образом: введите описание изображения здесь

    Вы могли бы сделать это, как показано ниже.

     $array = array( "a" => "apple", "b" => "banana", "c" => "catnip" ); foreach ($array as $a_key => $a_val) { $json .= "\"{$a_key}\" : \"{$a_val}\",\n"; } header('Content-Type: application/json'); echo "{\n" .rtrim($json, ",\n") . "\n}"; 

    Выше будет выводиться вроде Facebook.

     { "a" : "apple", "b" : "banana", "c" : "catnip" } 

    Простой способ для php> 5.4: как в графе Facebook

     $Data = array('a' => 'apple', 'b' => 'banana', 'c' => 'catnip'); $json= json_encode($Data, JSON_PRETTY_PRINT); header('Content-Type: application/json'); print_r($json); 

    Результат в браузере

     { "a": "apple", "b": "banana", "c": "catnip" } 

    Если у вас есть JSON $ ugly_json:

     echo nl2br(str_replace(' ', '&nbsp;', (json_encode(json_decode($ugly_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)))); 

    Классический корпус для рекурсивного решения. Вот мой:

     class JsonFormatter { public static function prettyPrint(&$j, $indentor = "\t", $indent = "") { $inString = $escaped = false; $result = $indent; if(is_string($j)) { $bak = $j; $j = str_split(trim($j, '"')); } while(count($j)) { $c = array_shift($j); if(false !== strpos("{[,]}", $c)) { if($inString) { $result .= $c; } else if($c == '{' || $c == '[') { $result .= $c."\n"; $result .= self::prettyPrint($j, $indentor, $indentor.$indent); $result .= $indent.array_shift($j); } else if($c == '}' || $c == ']') { array_unshift($j, $c); $result .= "\n"; return $result; } else { $result .= $c."\n".$indent; } } else { $result .= $c; $c == '"' && !$escaped && $inString = !$inString; $escaped = $c == '\\' ? !$escaped : false; } } $j = $bak; return $result; } } 

    Применение:

     php > require 'JsonFormatter.php'; php > $a = array('foo' => 1, 'bar' => 'This "is" bar', 'baz' => array('a' => 1, 'b' => 2, 'c' => '"3"')); php > print_r($a); Array ( [foo] => 1 [bar] => This "is" bar [baz] => Array ( [a] => 1 [b] => 2 [c] => "3" ) ) php > echo JsonFormatter::prettyPrint(json_encode($a)); { "foo":1, "bar":"This \"is\" bar", "baz":{ "a":1, "b":2, "c":"\"3\"" } } 

    ура

    print_r pretty print для PHP

    Пример PHP

     function print_nice($elem,$max_level=10,$print_nice_stack=array()){ if(is_array($elem) || is_object($elem)){ if(in_array($elem,$print_nice_stack,true)){ echo "<font color=red>RECURSION</font>"; return; } $print_nice_stack[]=&$elem; if($max_level<1){ echo "<font color=red>nivel maximo alcanzado</font>"; return; } $max_level--; echo "<table border=1 cellspacing=0 cellpadding=3 width=100%>"; if(is_array($elem)){ echo '<tr><td colspan=2 style="background-color:#333333;"><strong><font color=white>ARRAY</font></strong></td></tr>'; }else{ echo '<tr><td colspan=2 style="background-color:#333333;"><strong>'; echo '<font color=white>OBJECT Type: '.get_class($elem).'</font></strong></td></tr>'; } $color=0; foreach($elem as $k => $v){ if($max_level%2){ $rgb=($color++%2)?"#888888":"#BBBBBB"; }else{ $rgb=($color++%2)?"#8888BB":"#BBBBFF"; } echo '<tr><td valign="top" style="width:40px;background-color:'.$rgb.';">'; echo '<strong>'.$k."</strong></td><td>"; print_nice($v,$max_level,$print_nice_stack); echo "</td></tr>"; } echo "</table>"; return; } if($elem === null){ echo "<font color=green>NULL</font>"; }elseif($elem === 0){ echo "0"; }elseif($elem === true){ echo "<font color=green>TRUE</font>"; }elseif($elem === false){ echo "<font color=green>FALSE</font>"; }elseif($elem === ""){ echo "<font color=green>EMPTY STRING</font>"; }else{ echo str_replace("\n","<strong><font color=red>*</font></strong><br>\n",$elem); } } 

    1 – json_encode($rows,JSON_PRETTY_PRINT); возвращает префиксные данные с символами новой строки. Это полезно для ввода в командной строке, но, как вы обнаружили, в браузере это выглядит не так красиво. Браузер примет новые строки как источник (и, следовательно, просмотр источника страницы действительно покажет симпатичный JSON), но они не используются для форматирования вывода в браузерах. Браузеры требуют HTML.

    2 – используйте этот fuction github

     <?php /** * Formats a JSON string for pretty printing * * @param string $json The JSON to make pretty * @param bool $html Insert nonbreaking spaces and <br />s for tabs and linebreaks * @return string The prettified output * @author Jay Roberts */ function _format_json($json, $html = false) { $tabcount = 0; $result = ''; $inquote = false; $ignorenext = false; if ($html) { $tab = "&nbsp;&nbsp;&nbsp;"; $newline = "<br/>"; } else { $tab = "\t"; $newline = "\n"; } for($i = 0; $i < strlen($json); $i++) { $char = $json[$i]; if ($ignorenext) { $result .= $char; $ignorenext = false; } else { switch($char) { case '{': $tabcount++; $result .= $char . $newline . str_repeat($tab, $tabcount); break; case '}': $tabcount--; $result = trim($result) . $newline . str_repeat($tab, $tabcount) . $char; break; case ',': $result .= $char . $newline . str_repeat($tab, $tabcount); break; case '"': $inquote = !$inquote; $result .= $char; break; case '\\': if ($inquote) $ignorenext = true; $result .= $char; break; default: $result .= $char; } } } return $result; } 

    Следующее – то, что сработало для меня:

    Содержание test.php:

     <html> <body> Testing JSON array output <pre> <?php $data = array('a'=>'apple', 'b'=>'banana', 'c'=>'catnip'); // encode in json format $data = json_encode($data); // json as single line echo "</br>Json as single line </br>"; echo $data; // json as an array, formatted nicely echo "</br>Json as multiline array </br>"; print_r(json_decode($data, true)); ?> </pre> </body> </html> 

    вывод:

     Testing JSON array output Json as single line {"a":"apple","b":"banana","c":"catnip"} Json as multiline array Array ( [a] => apple [b] => banana [c] => catnip ) 

    Также обратите внимание на использование тега «pre» в html.

    Надежда, которая помогает кому-то

    Если вы работаете с MVC

    попробуйте сделать это в своем контроллере

     public function getLatestUsers() { header('Content-Type: application/json'); echo $this->model->getLatestUsers(); // this returns json_encode($somedata, JSON_PRETTY_PRINT) } 

    то, если вы вызываете / getLatestUsers, вы получите довольно JSON-выход;)

    У меня нет достаточной репутации, чтобы ответить Кендалу Хопкинсу, но я обнаружил ошибку в его претификаторе (это тоже было неловко)

    Эта строка должна быть изменена:

     if( $char === '"' && $prev_char != '\\' ) { 

    в

     if( $char === '"' && ($prev_char != '\\' && $prev_prev_char != '\\' ) { 

    Префикс разбивается и выдает недопустимый json, когда строка заканчивается обратным слэшем:

     "kittens\\"