www.webdeveloper.com
Results 1 to 10 of 10

Thread: Show path structure as HTML list

  1. #1
    Join Date
    Nov 2011
    Posts
    3

    Show path structure as HTML list

    I have an array of strings. The strings in the array look like this:

    The World
    The World/Europe/
    The World/Europe/Sweden/
    The World/Europe /Sweden/Stockholm
    The World/Europe/Sweden/Gothenburg
    The World/Europe/Finland/
    The World/Europe/Finland/Helsinki

    I want to present this as an unordered list like this in HTML:

    <ul>
    <li>The world
    <ul>
    <li>Europe
    <ul>
    <li>Sweden
    <ul>
    <li>Stockholm</li>
    <li>Gothenburg</li>
    </ul>
    </li>
    <li>Finland
    <ul>
    <li>Helsinki</li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>

    How do I do this?

  2. #2
    Join Date
    Aug 2007
    Posts
    3,767
    Code:
    var myName = (function () {
      function mkEl(a) {
        var ul = document.createElement("ul");
        if (a.every(function(v){return !/\//.test(v);})) {
            a.filter(function(e) {
              return e.length;
            }).forEach(function(e) {
              var li = document.createElement("li");
              li.appendChild(document.createTextNode(e));
              ul.appendChild(li);
            });
          return ul;
        }
        a.map(function (e) {
            return e.split("/");
          }).filter(function (e,i,a) {
            return (!i && e[0].length) || (i && e[0] != a[i-1][0]);
          }).forEach(function(e) {
            var li = document.createElement("li");
            li.appendChild(document.createTextNode(e[0]));
            var r = new RegExp("^"+e[0]+"\/");
            li.appendChild(mkEl(a.filter(function (e) {
                return r.test(e);
              }).map(function (e) {
                return e.replace(r,"");
              })));
            ul.appendChild(li);
          });
        return ul;
      }
      return mkEl;
    })();
    That's the best I can come up with. It's a little complicated, but it's actually simpler than anything else I thought of using the DOM elements. If you need to support IE8 (as you very probably do), you'll need the array functions from MDC. I use, every, map, filter and forEach. slice has been supported for ages as far as I can remember.

    BTW, I presume there's typo in your sample, it should be "The World/" right? If not, my code won't work.
    EDIT: Well, I didn't think it would, but it does! In fact, by testing, and it seems logical, all you have to do is list the city names and full path and it'll generate the correct DOM tree.

    Further addition, performance of something like this in JavaScript on a very large list is likely to be absolutely horrific, it could be optimised. For example, the .filter().map() combinations could be just one forEach, same with .filter().forEach() or if performance is really bad, just an old-fashioned iteration using a normal for loop. The a.map().filter().forEach() could be simplified into a few for loops too.

    One final thing to note is that if you have an array like, ["The World/","The World/Europe","The World/Africa","The World/Europe/Finland"], you'll need to sort that before you pass it to mkEl, and myName can be anything of your choice, it won't affect the recursion.
    Last edited by Declan1991; 11-09-2011 at 11:57 AM. Reason: Correction & Addition

  3. #3
    Join Date
    Nov 2011
    Posts
    3
    Hi,

    Thanks so much for answering, sorry for the late reply from me.

    I will give this a whirl right now and let you know what happens!

    /Hannes

  4. #4
    Join Date
    Nov 2011
    Posts
    3
    It works exactly like I thought! Million thanks. I will now try to understand what the heck you did and try to do some of the kaizen you suggested (if it needs it). The final list will contain different data and be around 5000 lines long so we'll see about performance.

  5. #5
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,270
    A more elementary solution...
    Code:
    (function(){
    	// a string with a split at the end
    	var arr="The World,The World/Europe/,The World/Europe/Sweden/,The World/Europe/Sweden/Stockholm,The World/Europe/Sweden/Gothenburg,The World/Europe/Finland/,The World/Europe/Finland/Helsinki".split(/,/g);
    	c='';
    	for (var l=arr.length,i=0;i<l;i++) c+='<li>'+arr[i].replace(/([^\/]+\/)(?!$)/g,'')+'</li>\n';
    	c=c.replace(/\/</g,'<');
    	alert(c);
    	// to insert in some container...
    	// document.getElementById('myDiv').innerHTML='<ul>'+c+'</ul>';
    })();
    The regular expression replaces all the preceding motives with a negative assertion (?!$). It remains to eliminate the last conditionals slashes, what can be made on the whole string (if there is followed by <).
    The whole is incorporated into an anonymous function executed at once.

    Edit: Variant - with a comma or a dollar, the regular expression could be applied to the whole initial string !
    Last edited by 007Julien; 11-11-2011 at 08:08 AM. Reason: Complement

  6. #6
    Join Date
    Aug 2007
    Posts
    3,767
    007Julien, that's not how I envisaged the code should work anyway, I know no other way of getting a nested list without some sort of recursion. I'm sure that there's a way to generate a string (rather than the DOM methods I used) in an easier fashion, but I'm just not sure right now.

  7. #7
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,270
    Perhaps this variant
    Code:
    (function(){
    	// a simple string (obtained, for example, with one array.join(',');) 
    	var arr="The World,The World/Europe/,The World/Europe/Sweden/,The World/Europe/Sweden/Stockholm,The World/Europe/Sweden/Gothenburg,The World/Europe/Finland/,The World/Europe/Finland/Helsinki";
    	var lst=arr.replace(/[^\/,]+\/(?!,)(?!$)/g,'').replace(/\//g,'').replace(/,/g,'</li><li>');
    	alert('<ul><li>'+lst+'</li></ul>');
    })();
    We remove at first, all sub-patterns which do not (^ at the beginning of the square brackets []) contains slash (/ with an backslash before) nor comma (,) one or more (+) following by a slash (/ with an other backslash before) and not following with a comma (?!,) nor following with the end of the string (?!$) ... Ouf !

    EDIt : Sorry i miss the question. I had not seen the different lists...
    Last edited by 007Julien; 11-11-2011 at 06:54 PM.

  8. #8
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,270
    There is nevertheless a solution with regular expressions
    HTML Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html lang="fr">
    <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="generator" content="PSPad editor, www.pspad.com">
    <title>Untitled</title>
    <style type="text/css">
    </style>
    </head>
    <body>
    <p>The whished answer</p>
    <ul>
    	<li>The world 
    	<ul>
    		<li>Europe 
    		<ul>
    			<li>Sweden 
    			<ul>
    				<li>Stockholm
    				</li>
    				<li>Gothenburg
    				</li>
    			</ul>
    			</li>
    			<li>Finland 
    			<ul>
    				<li>Helsinki
    				</li>
    			</ul>
    			</li>
    		</ul>
    		</li>
    	</ul>
    	</li>
    </ul>
    </div>
    <p>The obtained answer</p>
    <div id="rsl"></div>
    <script type="text/javascript">
    (function(){
    	// a string 
    	var str="The World,The World/Europe/,The World/Europe/Sweden/,The World/Europe/Sweden/Stockholm,The World/Europe/Sweden/Gothenburg,The World/Europe/Finland/,The World/Europe/Finland/Helsinki";
    	var oldNiv=-1,newNiv;
    	var lst=str.replace(/([^,]+)(?=,|$)/g,function(a){var b;
    		a=a.replace(/\/$/g,''); // No more end slash
    		newNiv=a.replace(/[^\/]+/g,'').length;// The number of slashs give the level (or niveau)
    		b=a.replace(/([^\/]+\/)/g,'');// The last word(s)
    		if (oldNiv<newNiv) r='<ul><li>'+b+'</li>';
    		if (newNiv==oldNiv) r='<li>'+b+'</li>';
    		if (newNiv<oldNiv) r='</ul><li>'+b+'</li>';
    		oldNiv=newNiv;
    		return r});
    	while(-1<--newNiv) lst+='</ul></li>';
    	lst+='</ul>';
    	lst=lst.replace(/,/g,'');
    	alert(lst)		
    	document.getElementById('rsl').innerHTML=lst;
    })();
    </script>
    </body>
    </html>
    JavaScript replace method takes too functions as arguments !
    Last edited by 007Julien; 11-11-2011 at 08:26 PM.

  9. #9
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,270
    Still some adjustments. The night wears advice...
    Code:
    <script type="text/javascript">
    (function(){
    	// a string 
    	var str="The World,The World/Europe/,The World/Europe/Sweden/,The World/Europe/Sweden/Stockholm,The World/Europe/Sweden/Gothenburg,The World/Europe/Finland/,The World/Europe/Finland/Helsinki";
    	var oldLvl=-1;newLvl;
    	var lst=str.replace(/([^,]+)(,|$)/g,function(t,a){var b;
    		a=a.replace(/\/$/g,''); // no more end slash
    		newLvl=a.replace(/[^\/]+/g,'').length;// the number of slashs give the level
    		b=a.replace(/([^\/]+\/)/g,'');// the last word
    		if (oldLvl<newLvl) r='\n<ul><li>'+b;
    		if (newLvl==oldLvl) r='</li>\n<li>'+b;
    		if (newLvl<oldLvl) r='</li></ul></li>\n<li>'+b;
    		oldLvl=newLvl;
    		return r});
    	while(-1<newLvl--) lst+='</li></ul>\n';
    	alert(lst)		
    	document.getElementById('rsl').innerHTML=lst;
    })();
    </script>
    Ouf ! It is finally difficult to make simple...
    Last edited by 007Julien; 11-12-2011 at 05:37 AM.

  10. #10
    Join Date
    Sep 2007
    Location
    istanbul
    Posts
    317
    Code:
      
    
    <style type="text/css">
    table td{ width:40px; border:1px solid red;}
    </style>
    <script type="text/javascript">
    
    // http://www.webdeveloper.com/forum/showthread.php?t=253188
    
    function fromTableToList(myid) {
    var el= document.getElementById(myid);
    var tr= el.getElementsByTagName('tr');
    //alert(tr.length);
    var B=[];
    var C=[];
    for(var i=0; i<tr.length; i++) {
    var td=tr[i].getElementsByTagName('td');
    B[i]=td.length;
    C[i]= td[B[i]-1].innerHTML;
    }
    //alert(B);
    //alert(C);
    
    var liste="<ul><li>"+C[0]; 
    for(var t=0,m=1; t<B.length; t++, m++) {
    
    if(B[m]>B[t]) { liste+="<ul><li>"+C[m]; }
    if(B[m]==B[t]) {liste+="</li><li>"+C[m]+"</li>";}
    if(B[m]<B[t]){liste+="</ul></li><li>"+C[m];}
    
    }
    
    //alert(liste);
    
    var ulli=liste.match(/<ul><li>/g).length;
    //alert(ulli);// 5
    var liul=liste.match(/<\/li><\/ul>/g).length;
    //alert(liul); // 1
    for(var k=0; k<(ulli-liul); k++) {
    liste+= "</li></ul>"
    }
    //alert(liste);
    
    var div=document.getElementById('myliste');
    div.innerHTML= liste;
    
    }
    
    function makeTable() {
    var s= "The World,The World/Europe/,The World/Europe/Sweden/,The World/Europe /Sweden/Stockholm,The World/Europe/Sweden/Gothenburg,The World/Europe/Finland/,The World/Europe/Finland/Helsinki";
    var table= "<table id=\"mytable\">";
    var A= s.split(",");
    //alert(A);
    
    for(var i=0; i<A.length; i++) { 
    table+="<tr>";
    
    var n= A[i].match(/[^\/]+/g);
    //alert(n);
    
    	for(var ii=0; ii<n.length; ii++) {
    
    	if(n[ii]!=n[n.length-1]) { table+= "<td></td>"; }
    	if(n[ii]==n[n.length-1]) {table+= "<td>"+n[ii]+"</td>";};
    	}
    	table+="</tr>";
    }
      table+="</table>";
      
    //alert("table =   "+table);
    var mytablo=document.getElementById('mydiv');
    mytablo.innerHTML=table;
    
    }
    
    
    
    </script>
    
    <body>
    <div id="mydiv"></div>
    <input type="button" onclick="makeTable()" value="make table">
    <div id="myliste"></div>
    <input type="button" onclick="fromTableToList('mytable')" value="from table to list">
    
    
    <p>The whished answer</p>
    <ul>
    <li>The world
    <ul>
    <li>Europe
    <ul>
    <li>Sweden
    <ul>
    <li>Stockholm</li>
    <li>Gothenburg</li>
    </ul>
    </li>
    <li>Finland
    <ul>
    <li>Helsinki</li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles