I having some problems generating a full tree of my db(sitemap). I reached a level that i want to write better code. Thats why i choose a recursive function for this puzzle.
I want to generate a endless unordered list.
Like so:
<ul>
<li><a></a>
<ul>
<li><a></a>(subs)
etc etc etc.....
</ul>
</li>
</ul>
Like i already said i tried the following:
<?php
function traverseArray($array, $sub=false)
{
foreach($array as $cat)
{
if(isset($cat['childeren']) && is_array($cat['childeren']))
{
//a category with subs
echo('<ul id="'.$cat['parent_cat_id'].'" class="lv0">');
echo('<li id="'.$cat['parent_cat_id'].'"><a href=#>'.$cat['name'].'</a>'."\n");
traverseArray($cat['childeren'], true);
}else{
if($sub){
//a sub category of category
echo('</ul></li>');
echo('<li id="'.$cat['parent_cat_id'].'"><a href=#>'.$cat['name'].'</a></li>'."\n");
}else{
//category with no subs
echo('<ul id="'.$cat['parent_cat_id'].'" class="lv0">');
echo('<li id="'.$cat['parent_cat_id'].'"><a href=#>'.$cat['name'].'</a></li>'."\n");
echo('</ul>');
}
}
}
}
traverseArray($sitemap);
?>
but this is a puzzle i cant figure out properly,
this the result so far(messy):
<ul id="0" class="lv0">
<li id="0"><a href=#>Headsets</a>
</ul></li>
<li id="1"><a href=#>(USB) headsets ....</a></li>
</ul></li>
<li id="1"><a href=#>... headsets</a></li>
</ul></li>
<li id="1"><a href=#>.. USB headsets</a></li>
</ul></li>
<li id="1"><a href=#>Bluetooth headsets</a></li>
<ul id="0" class="lv0">
<li id="0"><a href=#>Unified Communications</a></li>
A big mess!
The $sitemap array looks like this:
Array
(
[0] => Array
(
[category_id] => 1
[parent_cat_id] => 0
..........etc
........etc
[type] => cat
[childeren] => Array
(
[0] => Array
(
[category_id] => 2
[parent_cat_id] => 1
.......etc
[type] => cat
[childeren] => Array
(
[0] => Array
(
[category_id] => 32
[parent_cat_id] => 16
.......etc
[type] => series
)
)
So childeren in childeren in childeren,
Is this the best way to do this/ on the right track?
Or are there beter ways out there?
Like sql tree's or something? or just again the old foreach in foreach ..(which i am trying to avoid this time).
Any help would be much appreciated!!!
Thanks in advance,
Jacob
"What is wrong with my code?" is not a question for stackoverflow.
Think about what 'traverseArray' function should do.
Your code is a mess.
Here is a cleaned example of array traversing.
Please fit it to your needs:
function traverseArray($array)
{
echo '<ul>';
foreach($array as $cat)
{
echo '<li>';
if(isset($cat['childeren']) && is_array($cat['childeren']))
{
echo '' . $cat['name'] . '';
traverseArray($cat['childeren']);
}
else
{
echo '' . $cat['name'] . '';
}
echo '</li>';
}
echo '</ul>';
}
traverseArray($sitemap);
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Lets say I have the array down here. I left out a few maps and files as this should be enough to make my point. There is no max depth to the array so there could be even more.
Array
(
[media] => Array
(
[documents] => Array
(
[0] => add.php
)
[music] => Array
(
[albums] => Array
(
[0] => add.php
)
)
[overview] => Array
(
[0] => overview.php
)
)
What I would like to get is something like the following:
<ul>
<li>Media
<ul>
<li>Documents
<ul>
<li>Add</li>
</ul>
</li>
<li>Music
<ul>
<li>Albums
<ul>
<li>Add</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</li>Overview
<ul>
<li>Overview</li>
</ul>
</li>
</ul>
I found php create navigation menu from multidimensional array dynamically but imo the accepted answer has quite a lot garbage and the result isn't quite of what I need. If you would like to know how the array is generated please let me know.
Thanks in advance for helping me
You need to use a recursive function that loops through your array. Something like this:
function outputMenu(array $array, $baseUrl = '/')
{
$html = '';
foreach ($array as $key => $item)
{
if (is_array($item))
{
$html .= '<li>'.$key.'<ul>';
$html .= outputMenu($item, $baseUrl.$key.'/');
$html .= '</ul></li>';
}
else
{
$html .= '<li>'.ucfirst(substr($item, 0, -4)).'</li>';
}
}
return $html;
}
echo outputMenu($array);
$array = array(
'media'=>array('documents'=>array('add.php'),
'music'=>array('albums'=>array('add.php'))),
'overview'=>array('overview.php')
);
print_link($array);
function print_link($arre){
foreach($arre as $key => $arr){
if(is_array($arr)){
echo '<li>'. $key .'<ul>';
print_link($arr);//echo '<li>'.$arr.'</li>';
echo '</ul><li>';
} else {
echo '<li>'.$arr.'</li>';
}
}
}
you will need a function for this for this task
I am currently creating a joomla component, and i am currently stuck with the menu part.
this is in my model file:
public function getMenu(){
$menu_id = JRequest::getInt('id');
$db = $this->getDbo();
$query = $db->getQuery(true);
$query->select('t.country_name,t.country_code, a.continent_name');
$query->from('#__vectormap_countries AS t')
->join('LEFT', '#__vectormap_continents AS a USING(continent_id)')
->where('t.published = 1');
$db->setQuery($query);
$menu_items = $db->loadObjectList();
return $menu_items;
}
and on the front end i have:
<?php $menus = $this->menu ?>
<?php foreach($menus as $menu): ?>
<div><?php echo $menu->continent_name ?></div>
<li id="<?php echo $menu->country_code ?>"><?php echo $menu->country_name ?></li>
<br />
<?php endforeach; ?>
and that returns:
Africa
South Africa
Africa
Mozambique
or if i print out the array this:
Array ( [0] => stdClass Object ( [country_name] => South Africa [country_code] => ZA [continent_name] => Africa ) [1] => stdClass Object ( [country_name] => Mozambique [country_code] => MZ [continent_name] => Africa ) ) 1
Now Finally the question, how would i sort it so that Africa (continent_name) not be repeated but rather have all the countries that have the continent_name of Africa list underneath it?
Keep in mind North America and such will also come in to play..
Summarized question -> How would I sort countries underneath there associated continents fond in the array.
Any Help Greatly Appreciated thanks.
how would i sort it that everything
The easy fix is by ORDERing your query results and then add some logic in your foreach loop
$query->order('a.continent_name ASC, t.country_name ASC');
In your foreach loop remember what the previous continent was
<?php
$lastcontinent = "";
foreach($menus as $k => $menu):
if($lastcontinent != $menu->continent_name){
if($k > 0){ // if this isn't the first continent
// closing tags for the previous continent
echo '</ul></div>';
}
echo '<div>'.$menu->continent_name.'</div><ul>';
}
$lastcontinent = $menu->continent_name;
echo '<li id="'.$menu->country_code.'">'.$menu->country_name.'</li>';
endforeach;
?>
</ul></div> <!-- closing tags for the last continent which hasn't been closed yet -->
Use a foreach loop and make a new array and create continent_name as a key. Then you won't have a repetitive names.
Here is what I have so far:
My string:
$str = "<ul>
<li><a name="valuehere1" title="titlehere" href="/channel/london/">Link1</a></li>
<li><a name="valuehere2" title="titlehere" href="/channel/games/">Link1</a></li>
<li><a name="valuehere3" title="titlehere" href="/channel/sport/">Link1</a></li>
</ul>";
My PHP so far (and I am stuck):
$dom = new domDocument;
$dom->loadHTML($str);
$children = $dom->getElementsByTagName('li')->item(0)->childNodes->getAttribute('name');
$out = array();
foreach ($children as $child) {
$out[] = $dom->saveXML($child);
}
I am trying to extract the NAME attribute value of the A tag in the LI base on a match (in this example they are "london", "games", "sport") . WHen I pass "games" it should give me the output as "valuehere2". This has to be done at the server side due to some restrictions I have. Can someone help me with this please?
Thanks,
L
You've almost got it. But your code is fetching an attribute of the first li it finds, and tries to use that attribute value as an array to loop on. What you want is:
$children = $dom->getElementsByTagName('li');
$out = array();
foreach ($children as $child) {
if ($child->item(0)->childNodes->getAttribute('name')) {
$out[] = $dom->saveXML($child);
}
}
getElementsByTagName returns an DOMElementList (or whatever), which is an iterable array. Doing the getAttribute() stuff simply returns a string.
Regular expressions to the rescue?
[~]% cat test.php
<?php
$str = '<ul>
<li><a name="valuehere1" title="titlehere" href="/channel/london/">Link1</a></li>
<li><a name="valuehere2" title="titlehere" href="/channel/games/">Link1</a></li>
<li><a name="valuehere3" title="titlehere" href="/channel/sport/">Link1</a></li>
</ul>';
preg_match_all('/<li><a name="(.*)" title/', $str, $m);
print_r($m);
?>
[~]% php test.php
Array
(
[0] => Array
(
[0] => <li><a name="valuehere1" title
[1] => <li><a name="valuehere2" title
[2] => <li><a name="valuehere3" title
)
[1] => Array
(
[0] => valuehere1
[1] => valuehere2
[2] => valuehere3
)
)
I wrote a recursive function, which returns an array with the paths to all files/folders in a given path. An array is already sorted and returns the exact information i want, but i struggle to display it properly in html lists.
Array_of_paths = (
[0] => /path/to/folderA/
[1] => /path/to/folderA/subfolderAA/
[2] => /path/to/folderB/
[3] => /path/to/folderB/subfolderBB/
[4] => /path/to/folderB/subfolderBB/fileBB.txt
[5] => /path/to/folderB/fileB.txt
[6] => /path/to/folderC/
...
)
I want to put these paths in <ul>,<li> tags to see something like this:
<ul>
<li>/path/to/folderA/
<ul>
<li>/path/to/folderA/folderAA/</li>
</ul>
</li>
<li>/path/to/folderB
<ul>
<li>/path/to/folderB/subfolderBB/
<ul>
<li>/path/to/folderB/subfolderBB/fileBB.txt</li>
</ul>
</li>
<li>/path/to/folderB/fileB.txt</li>
</ul>
</li>
<li>/path/to/folderC/</li>
</ul>
=>
<ul>
<li>/path/to/folderA/
<ul>
<li>/path/to/folderA/folderAA/</li>
</ul>
</li>
<li>/path/to/folderB
<ul>
<li>/path/to/folderB/subfolderBB/
<ul>
<li>/path/to/folderB/subfolderBB/fileBB.txt</li>
</ul>
</li>
<li>/path/to/folderB/fileB.txt</li>
</ul>
</li>
<li>/path/to/folderC/</li>
</ul>
I managed to find a couple of similars questions, but the answers were in Ruby language. So, what's the problem solving idea behind this?
$lastD = 0;
foreach ($p as $e)
{
$depth = substr_count($e, '/');
//if this is a file, then add one to the depth count
if (substr($e,-1) != '/')
$depth++;
if ($depth > $lastD)
{
echo "<ul>";
$lastD = $depth;
}
if ($depth < $lastD)
{
echo "</ul>";
$lastD = $depth;
}
echo "<li>$e";
}
Returns:
/path/to/folderA//path/to/folderA/subfolderAA//path/to/folderB//path/to/folderB/subfolderBB//path/to/folderB/subfolderBB/fileBB.txt/path/to/folderB/fileB.txt/path/to/folderC/
If your are in PHP5, use RecursiveDirectoryIterator and RecursiveIteratorIterator to do the job.
$dir = new RecursiveDirectoryIterator("/path");
$it = new RecursiveIteratorIterator($dir);
foreach ($it as $key => $value) {
// Use $it->getDepth() and $value->getRealpath()
// with Byron's code to generate your list
}
I'm using this bit of code you published.
The structure of nested UL's is not quite right, so I just added a quick fix in order to have the closing ul tags so it can be used with more levels.
....
if ($depth < $lastD)
{
$closingULs=$lastD-$depth;
for($i=0;$i<$closingULs;$i++)
{
$uls.="</ul>";
}
echo $uls;
$lastD = $depth;
}
IMHO it's better to store the data in a more efficient and more similar format, something hierarchical. You can explode() your array by / and create the tree via arrays, then it'll be easy to foreach the array and build the HTML list.
foreach ( $paths as $path )
{
$pieces = explode('/', $path);
foreach ( $pieces as $piece )
{
$pathtree[$piece] = '';
}
}
This new $pathtree array is much smaller, probably 1/4th as small as your $paths array. From this point you just need to foreach it to build your HTML list tree.
I have a pretty simple problem.
Basically I have an array called $list that is a list of titles. If I do a print_r($list) I get these results:
Array ( [0] => Another New Title [1] => Awesome Movies and stuff [2] => Jascha's Title )
Now, I'm running a foreach loop to retrieve their values and format them in an <ul> like so...
function get_film_list(){
global $categories;
$list = $categories->get_film_list();
if(count($list)==0){
echo 'No films are in this category';
}else{
echo '<ul>';
foreach($list as $title){
echo '<li>' . $title . '<li>';
}
echo '</ul>';
}
}
The problem I'm having is my loop is returning two values per value (is it the key value?)
The result of the preceding function looks like this:
Another New Title
Awesome Movies and stuff
Jascha's Title
I even tried:
foreach($list as $key => $title){
echo '<li>' . $title . '<li>';
}
With the same results:
Another New Title
Awesome Movies and stuff
Jascha's Title
What am I missing here?
Thanks in advance.
You’re using <li> instead of </li> as closing tag. Use the proper closing tag and it should work:
echo '<li>' . $title . '</li>';