PHP: pretty print JSON as coloured HTML

Today I wanted a way to pretty-print a JSON string with colour highlighting. I went looking and found a bunch of ‘pretty print’ functions, but none with colour, so I implemented my own

Usage:

  1. Include the relevant CSS for formatting your prettified JSON. There’s example CSS in the code below. You can do:
    echo("<style>".Convert::jsonPrettyHtmlCSS()."</style>");
  2. Call Convert::json2PrettyHTML(), e.g:
    echo(Convert::json2PrettyHTML('["a",{"foo":"bar","baz":42}]'));

    ….And the code:

    
    <?php
    
    class Convert {
    	
    	/**
    	 * Helper for Convert::prettyJSON()
    	 * Returns a HTML <span> with a class matching the data type (integer,string,double,etc)
    	 * 	Add css to colour the values according to type.
    	 * 
    	 * autodetects numeric strings and treats them as numbers 
    	 * 
    	 * runs htmlentities() and wordwrap() on values (wraps at 100 chars)
    	 * 
    	 * @param mixed $val	value to beautify
    	 * @param int $indents	number of indents
    	 * @param bool $isKey	true if this is a key name
    	 * @return HTML
    	 * @see Convert::prettyJSON()
    	 * @see Convert::json2PrettyHTML() 
    	 * 
    	 */
    	private static function jsonColor($val,$indents=1,$isKey=false) {
    		//echo print_r($val,true) . ": " . gettype($val) . "\n";
    		$type = gettype($val);
    		
    		if (($type == "string") && is_numeric($val)) {
    			//try to convert it to a number
    			$val = floatval($val);
    			
    			if (intval($val) == $val)	//convert from float to int if it's a whole number: 
    				$val = intval($val);
    			
    			$type = gettype($val);
    		}
    		
    		//$type = gettype($val);
    		
    		$color = "";
    		switch($type) {
    			case 'string':
    				$val = '"' . $val . '"';
    				break;
    			case 'array':
    				$val = self::prettyJSON($val,$indents);
    				break;
    		}
    		$val = wordwrap(htmlentities($val),100,"<br />",true);
    		
    		if ($isKey) $type = $type . " key";
    		
    		return "<span class='$type'>" . //"' style='color:$color;'>" 
    			"$val</span>"; // . " (" . gettype($val) . ")";
    	}
    	
    	/**
    	 * Helper for Convert::json2PrettyHtml()
    	 * convert a value (i.e from json_decode) into a pretty colourised string
    	 * @param array|string|number $json		value to prettify
    	 * @param number $indents				indentation level (used for recursion)
    	 * @return string
    	 * @see Convert::json2PrettyHTML()
    	 */
    	private static function prettyJSON($json,$indents = 1) {
    		$ret = "";
    		$indent=str_repeat("<span class='indent'> </span>",$indents);
    		if (is_array($json) || is_object($json) ) {
    			foreach ($json as $k => $v) {
    				$k = htmlentities($k);
    				if (is_array($v) || is_object($v)) {
    					$v = self::prettyJson($v,$indents+1);
    					$ret .= ($ret ? ",<br />\n" : "") . $indent .
    						self::jsonColor($k,$indents,true) . ":\t<br />$v";
    				} else {
    					$ret .= ($ret ? ",<br />\n" : "") . $indent .
    						self::jsonColor($k,$indents,true) . ":\t" . self::jsonColor($v,$indents);
    				}
    			}
    			if (is_object($json)) {
    				$openbrace = "{";
    				$closebrace = "}";
    			} else {
    				$openbrace = "[";
    				$closebrace = "]";
    			}
    			$outdent=str_repeat("<span class='indent'> </span>",$indents-1);
    			$ret = "$outdent$openbrace<br />\n$ret<br />\n$outdent$closebrace";
    		} else
    			$ret = self::jsonColor($json,$indents);
    		
    		return $ret;
    		
    	}
    	
    		/**
    	 * Return or add some CSS for json2PrettyHTML to the requirements
    	 * @param string $return	if true, return the CSS. Otherwise insert it using Requirements::customCSS()
    	 * @return string | void
    	 * @see Convert::json2PrettyHTML()
    	 */
    	public static function jsonPrettyHtmlCSS($return = true) {
    		return 'span.json .integer, span.json .double {
    				color: #700;
    				font-family: mono;
    			}
    			
    			span.json .string {
    				color: #070;
    				font-family: mono;
    			}
    			
    			
    			span.json .key.string {
    				color: #007;
    			}
    			
    			span.json .key.integer, span.json .key.double {
    				color: #707;
    			}
    			
    			
    			span.json .indent {
    				padding-left: 40px;
    			}';
    	}
    	
    	/**
    	 * Converts a JSON string to pretty, readable HTML output which can be 
    	 * 	colourised/customised via CSS
    	 * 
    	 * Also does other nice things, like word wrapping at 100 chars, running 
    	 * 	values through htmlentities(), and treating numeric strings as numbers
    	 * 
    	 * Include CSS to style the output (set colours, indent width, etc)
    	 * Notes: 
    	 * 		- everything will be wrapped in a span.json (i.e <span> with 'json' 
    	 * 			as the class, css: span.json)
    	 * 		- keys will be spans with the'key' class  ( e.g span.key )
    	 * 		- values and keys will be spans and will have the datatype as the 
    	 * 			class ( span.integer, span.key.integer)
    	 * 		- there will be empty spans with the 'indent' class in the 
    	 * 			appropriate places. There may be more than one consecutively. 
    	 * 
    	 * Example CSS is returned by the jsonPrettyHtmlCSS() function
    			
    	 * @param string $json	the json to beautify
    	 * @return HTML
    	 * @see Convert::jsonPrettyHtmlCSS()
    	 */
    	public static function json2PrettyHTML($json) {
    		return "<span class='json'>" . self::prettyJSON(json_decode($json)) . "</span>";
    	}
    }
    
    
    
    

    I hope someone finds this useful! :)

Leave a Reply