0

The following almost works but if i remove the <a> the json breaks with an empty node name:" " and also i believe i am creating an array while i need the json in the format below. Here it is a jsFiddle too (see below the result for the output i am looking for).

What I am trying to do is to generate an object I can read from a nested list in order to generate a mind map (D3) like this

HTML

<div id="tree">
<ul class="sortable">
  <li><a href="http://google.com">flare</a>
    <ul class="sortable">
      <li>analytics
        <ul class="sortable">
          <li><a href="http://google.com">cluster</a>
            <ul class="sortable">
              <li><a href="http://google.com">AgglomerativeCluster</a></li>
              <li><a href="http://google.com">CommunityStructure</a></li>
              <li><a href="http://google.com">HierarchicalCluster</a></li>
              <li><a href="http://google.com">MergeEdge</a></li>
            </ul>
          </li>
          <li><a href="http://google.com">graph</a>
            <ul class="sortable">
              <li><a href="http://google.com">BetweennessCentrality</a></li>
              <li><a href="http://google.com">LinkDistance</a></li>
              <li><a href="http://google.com">MaxFlowMinCut</a></li>
              <li><a href="http://google.com">ShortestPaths</a></li>
              <li><a href="http://google.com">SpanningTree</a></li>
            </ul>
          </li>
          <li><a href="http://google.com">optimization</a>
            <ul class="sortable">
              <li><a href="http://google.com">AspectRatioBanker</a></li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="http://google.com">Pippo</a></li>
  <li><a href="http://google.com">buonanotte</a></li>
  <li><a href="http://google.com">Avantieri</a></li>
</ul>
</div>
<div id="d" style="margin-top: 40px; padding-top: 20px;">Output:<br><br><pre></pre></div>


<div id="d" style="margin-top: 40px; padding-top: 20px;">Output:<br><br><pre></pre></div>
<div id="json_results" style="margin-top: 40px; padding-top: 20px;">
Needs to become:
  <pre style="padding-top: 20px;">
var root = JSON.parse( ' {
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster","url":"http://google.com"},
      {"name": "CommunityStructure"},
      {"name": "HierarchicalCluster"},
      {"name": "MergeEdge"}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality" },
      {"name": "LinkDistance" },
      {"name": "MaxFlowMinCut" },
      {"name": "ShortestPaths" },
      {"name": "SpanningTree" }
     ]
    },
    {
     "name": "optimization",
     "children": [
      {"name": "AspectRatioBanker" }
     ]
    }
   ]
  },
  {"name": "Pippo"},
  {"name": "buonanotte" },
  {"name": "Avantieri"}
 ]
} ') ;
  </pre>
</div>

JS

$(document).ready(function () {
    var out = [];
    function processOneLi(node) {       
        var aNode = node.children("a:first");
        var retVal = {
            "name": aNode.text(),
            "url": aNode.attr("href")
        };
        node.find("> .sortable > li").each(function() {
            if (!retVal.hasOwnProperty("children")) {
                retVal.children = [];
            }
            retVal.children.push(processOneLi($(this)));
        });
        return retVal;
    }
    $("#tree > ul > li").each(function() {
        out.push(processOneLi($(this)));
    });
    $('#d pre').text(JSON.stringify(out, null, 2));

});

The json should become:

var root = JSON.parse( ' {
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster","url":"http://google.com"},
      {"name": "CommunityStructure"},
      {"name": "HierarchicalCluster"},
      {"name": "MergeEdge"}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality" },
      {"name": "LinkDistance" },
      {"name": "MaxFlowMinCut" },
      {"name": "ShortestPaths" },
      {"name": "SpanningTree" }
     ]
    },
    {
     "name": "optimization",
     "children": [
      {"name": "AspectRatioBanker" }
     ]
    }
   ]
  },
  {"name": "Pippo"},
  {"name": "buonanotte" },
  {"name": "Avantieri"}
 ]
} ') ;

but this is what i get instead:

[
  {
    "name": "flare",
    "url": "http://google.com",
    "children": [
      {
        "name": "",
        "children": [
          {
            "name": "cluster",
            "url": "http://google.com",
            "children": [
              {
                "name": "AgglomerativeCluster",
                "url": "http://google.com"
              },
              {
                "name": "CommunityStructure",
                "url": "http://google.com"
              },
              {
                "name": "HierarchicalCluster",
                "url": "http://google.com"
              },
              {
                "name": "MergeEdge",
                "url": "http://google.com"
              }
            ]
          },
          {
            "name": "graph",
            "url": "http://google.com",
            "children": [
              {
                "name": "BetweennessCentrality",
                "url": "http://google.com"
              },
              {
                "name": "LinkDistance",
                "url": "http://google.com"
              },
              {
                "name": "MaxFlowMinCut",
                "url": "http://google.com"
              },
              {
                "name": "ShortestPaths",
                "url": "http://google.com"
              },
              {
                "name": "SpanningTree",
                "url": "http://google.com"
              }
            ]
          },
          {
            "name": "optimization",
            "url": "http://google.com",
            "children": [
              {
                "name": "AspectRatioBanker",
                "url": "http://google.com"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "name": "Pippo",
    "url": "http://google.com"
  },
  {
    "name": "buonanotte",
    "url": "http://google.com"
  },
  {
    "name": "Avantieri",
    "url": "http://google.com"
  }
]

Here it is the jsFiddle (see below the result for the output i am looking for)

4
  • Just to clarify your problem is just why the empty node ? Commented Mar 27, 2017 at 14:31
  • @DaniP not only, basically the out i get isn't like the one i am expecting, see the 2 json for the differences and yes, if i remove a link tag it breaks Commented Mar 27, 2017 at 14:32
  • well it's better if you point exactly where is the difference instead of making us compare line by line the two JSON, you don't want the url: for all items ?... Btw I solved the issue from the empty name jsfiddle.net/k7vSg/126 Commented Mar 27, 2017 at 14:38
  • @DaniP sorry i thought it would help to provide as much details as possible Commented Mar 27, 2017 at 14:39

3 Answers 3

1

A small recursive function will do:

function listToObject(list) {
  return $(list).first().children("li").map(function () {
    var $this = $(this), $name = $this.children("a").first();
    return {
                            // see http://stackoverflow.com/a/8851526
      name: $name.text() || $this.clone().children().remove().end().text().trim(),
      url: $name.attr("href"),
      children: listToObject($this.children("ul"))
    };
  }).toArray();
}

var output = listToObject($("#tree > ul"));
console.log(output);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="tree">
  <ul class="sortable">
    <li><a href="http://google.com">flare</a>
      <ul class="sortable">
        <li>analytics
          <ul class="sortable">
            <li><a href="http://google.com">cluster</a>
              <ul class="sortable">
                <li><a href="http://google.com">AgglomerativeCluster</a></li>
                <li><a href="http://google.com">CommunityStructure</a></li>
                <li><a href="http://google.com">HierarchicalCluster</a></li>
                <li><a href="http://google.com">MergeEdge</a></li>
              </ul>
            </li>
            <li><a href="http://google.com">graph</a>
              <ul class="sortable">
                <li><a href="http://google.com">BetweennessCentrality</a></li>
                <li><a href="http://google.com">LinkDistance</a></li>
                <li><a href="http://google.com">MaxFlowMinCut</a></li>
                <li><a href="http://google.com">ShortestPaths</a></li>
                <li><a href="http://google.com">SpanningTree</a></li>
              </ul>
            </li>
            <li><a href="http://google.com">optimization</a>
              <ul class="sortable">
                <li><a href="http://google.com">AspectRatioBanker</a></li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </li>
    <li><a href="http://google.com">Pippo</a></li>
    <li><a href="http://google.com">buonanotte</a></li>
    <li><a href="http://google.com">Avantieri</a></li>
  </ul>
</div>

The output is a bit stricter than what you have asked for. Each object has a url and children, even if empty. This will actually make handling easier in the end.

Sign up to request clarification or add additional context in comments.

1 Comment

careful, we have an issue with the first node name "name": "flarePippobuonanotteAvantieri",
0

I found your problem, there was one li element that didn't have element which you were looking for.

This will get you the results you're looking

$(document).ready(function () {
    var out = [];
    function processOneLi(node) {
        var aNode = node.children("a:first");
        var retVal = {};
        if (aNode.text()) {
           retVal = {
              "name": aNode.text(),
              "url": aNode.attr("href")
           };
        } else {
          retVal = { "name": node.clone().children().remove().end().text().replace(/\r?\n|\r/g, " ") };
        }
        node.find("> .sortable > li").each(function() {
            if (!retVal.hasOwnProperty("children")) {
                retVal.children = [];
            }
            retVal.children.push(processOneLi($(this)));
        });
        return retVal;
    }
    $("#tree > ul > li").each(function() {
        out.push(processOneLi($(this)));
    });
    $('#d pre').text(JSON.stringify(out, null, 2));

});

7 Comments

Let it load. I had the same result until I waited a few seconds.
dunno i wait but it is still empty the output []
I got your results now, check the update to my answer.
almost, but i must admit that this one works jsfiddle.net/k7vSg/127 but when i paste that json output into jsfiddle.net/akq6oofa it doesn't works
@rob.m You have a lot of whitespaces in the JSON string so its making it difficult to parse. I updated the link for you. jsfiddle.net/akq6oofa/5 now has the better json string format.
|
0

Your problem is that Pippo, buonanotte and Avantieri are siblings of flare, instead of being nested under flare.

I think I got to the result you expected in this fiddle: http://jsfiddle.net/k7vSg/122/

HTML:

<div id="tree">
<ul class="sortable">
  <li><a href="http://google.com">flare</a>
    <ul class="sortable">
      <li>analytics
        <ul class="sortable">
          <li><a href="http://google.com">cluster</a>
            <ul class="sortable">
              <li><a href="http://google.com">AgglomerativeCluster</a></li>
              <li><a href="http://google.com">CommunityStructure</a></li>
              <li><a href="http://google.com">HierarchicalCluster</a></li>
              <li><a href="http://google.com">MergeEdge</a></li>
            </ul>
          </li>
          <li><a href="http://google.com">graph</a>
            <ul class="sortable">
              <li><a href="http://google.com">BetweennessCentrality</a></li>
              <li><a href="http://google.com">LinkDistance</a></li>
              <li><a href="http://google.com">MaxFlowMinCut</a></li>
              <li><a href="http://google.com">ShortestPaths</a></li>
              <li><a href="http://google.com">SpanningTree</a></li>
            </ul>
          </li>
          <li><a href="http://google.com">optimization</a>
            <ul class="sortable">
              <li><a href="http://google.com">AspectRatioBanker</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><a href="http://google.com">Pippo</a></li>
      <li><a href="http://google.com">buonanotte</a></li>
      <li><a href="http://google.com">Avantieri</a></li>
    </ul>
  </li>

</ul>
</div>



<div id="d" style="margin-top: 40px; padding-top: 20px;">Output:<br><br><pre></pre></div>
<div id="json_results" style="margin-top: 40px; padding-top: 20px;">
Needs to become:
  <pre style="padding-top: 20px;">
var root = JSON.parse( ' {
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster","url":"http://google.com"},
      {"name": "CommunityStructure"},
      {"name": "HierarchicalCluster"},
      {"name": "MergeEdge"}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality" },
      {"name": "LinkDistance" },
      {"name": "MaxFlowMinCut" },
      {"name": "ShortestPaths" },
      {"name": "SpanningTree" }
     ]
    },
    {
     "name": "optimization",
     "children": [
      {"name": "AspectRatioBanker" }
     ]
    }
   ]
  },
  {"name": "Pippo"},
  {"name": "buonanotte" },
  {"name": "Avantieri"}
 ]
} ') ;
  </pre>
</div>

JS:

$(document).ready(function () {
    var out = [];
    function processOneLi(node) {       
        var aNode = node.children("a:first");
        var retVal = {
            "name": aNode.text(),
            "url": aNode.attr("href")
        };
        node.find("> .sortable > li").each(function() {
            if (!retVal.hasOwnProperty("children")) {
                retVal.children = [];
            }
            retVal.children.push(processOneLi($(this)));
        });
        return retVal;
    }
    $("#tree > ul > li").each(function() {
        out.push(processOneLi($(this)));
    });

    $('#d pre').text(JSON.stringify(out[0], null, 2));

});

1 Comment

see we also have the issue of an empty object if no url is provided with the node, check your jsFiddle output

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.