Display JSON/YAML hierarchy as a tree in HTML?
I finally came up with a super-elegant way to do this in about 5 lines of code, based on the fact that the simple YAML looks a lot like Markdown.
We're starting off with this:
---
all:
foo: 1025
bar:
baz: 37628
quux:
a: 179
b: 7
Use regexps (in this case, in Perl) to remove the starting ---
, and put hyphens before the key on each line:
$data =~ s/^---\n//s;
$data =~ s/^(\s*)(\S.*)$/$1- $2/gm;
Voila, Markdown:
- all:
- foo: 1025
- bar:
- baz: 37628
- quux:
- a: 179
- b: 7
Now, just run it through a Markdown processor:
use Text::Markdown qw( markdown );
print markdown($data);
And you get an HTML list -- clean, semantic, backwards-compatible:
<ul>
<li>all:
<ul>
<li>foo: 1025</li>
<li>bar:</li>
<li>baz: 37628</li>
<li>quux:
<ul>
<li>a: 179</li>
<li>b: 7</li>
</ul>
</li>
</ul>
</li>
</ul>
YUI Treeview can enhance existing lists, so we wrap it all up:
<html>
<head>
<!-- CSS + JS served via YUI hosting: developer.yahoo.com/yui/articles/hosting/ -->
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?2.6.0/build/treeview/assets/skins/sam/treeview.css">
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.6.0/build/yahoo-dom-event/yahoo-dom-event.js&2.6.0/build/treeview/treeview-min.js"></script>
</head>
<body>
<div id="markup" class="yui-skin-sam">
<!-- start Markdown-generated list -->
<ul>
<li>all:
<ul>
<li>foo: 1025</li>
<li>bar:</li>
<li>baz: 37628</li>
<li>quux:
<ul>
<li>a: 179</li>
<li>b: 7</li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- end Markdown-generated list -->
</div>
<script type="text/javascript">
var treeInit = function() {
var tree = new YAHOO.widget.TreeView("markup");
tree.render();
};
YAHOO.util.Event.onDOMReady(treeInit);
</script>
</body>
</html>
So this all works out to about 5 lines of code (turn YAML into Markdown, turn Markdown into an HTML list, and place that HTML list inside a template HTML file. The generated HTML's progressively-enhanced / degradable, since it's fully viewable on non-JavaScript browsers as a plain old list.
You can convert your JSON data to nicely nested DIVs with this. I haven't tested it with a wide number of datasets, but it seems to work.
function renderJSON(obj) {
'use strict';
var keys = [],
retValue = "";
for (var key in obj) {
if (typeof obj[key] === 'object') {
retValue += "<div class='tree'>" + key;
retValue += renderJSON(obj[key]);
retValue += "</div>";
} else {
retValue += "<div class='tree'>" + key + " = " + obj[key] + "</div>";
}
keys.push(key);
}
return retValue;
}