views:

3183

answers:

4

I have YAML data that looks sort of like this, but ~150k of it:

---
all:
  foo: 1025
  bar:
    baz: 37628
    quux:
      a: 179
      b: 7

...or the same thing in JSON:

{"all":{"bar":{"baz":"37628","quux":{"a":"179","b":"7"}},"foo":"1025"}}

I want to present this content in an expandable JavaScripty HTML tree view (examples: 1, 2) to make it easier to explore. How do I do this?

I guess what I really want to figure out is how to take this YAML/JSON data, and automatically display it as a tree (with hash keys sorted alphabetically). So far, I've been tussling with YUI's tree view, but it doesn't accept straight JSON, and my feeble attempts to massage the data into something useful don't seem to be working.

Thanks for any help.

+2  A: 
Diodeus
That tool takes the JSON and turns it back into something that looks like the original YAML, but I guess I was looking for some way to have it be expandable/collapsible..
Anirvan
+1  A: 

Version 2.6 of YUI's TreeView now does take a JavaScript object but not in this format and won't sort it automatically. You would have to use YUI's JSON utility to convert it to an actual JavaScript which you will have to traverse. Your sample will have to be converted to something like this:

{label:"all", children[
    {label:"bar", children:[
     {label:"baz: 37628"},
     {label:"quux", children[
      {label:"a: 179"},
      {label:"b: 7"}
     ]},
     {label:"foo: 1025"}
    ]}
]}

I've probably missing some comma or something. Your incoming data might not be sorted so you will have to sort each array. Then, you just need to pass this object as the second argument to the TreeView constructor and the tree should appear.

+2  A: 

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) {
var keys = []
var 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

}

Diodeus
+3  A: 

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"&gt;
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.6.0/build/yahoo-dom-event/yahoo-dom-event.js&amp;2.6.0/build/treeview/treeview-min.js"&gt;&lt;/script&gt;
</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.

Anirvan