How do I go from this multidimensional array:
Array (
[Camden Town] => Array (
[0] => La Dominican
[1] => A Lounge
),
[Coastal] => Array (
[0] => Royal Hotel
),
[Como] => Array (
[0] => Casa Producto
[1] => Casa Wow
),
[Florence] => Array (
[0] => Florenciana Hotel
)
)
to this:
<ul>
<li>Camden Town</li>
<ul>
<li>La Dominican</li>
<li>A Lounge</li>
</ul>
<li>Coastal</li>
<ul>
<li>Royal Hotel</li>
</ul>
...
</ul>
above is in html...
//code by acmol
function array2ul($array) {
$out = "<ul>";
foreach($array as $key => $elem){
if(!is_array($elem)){
$out .= "<li><span>$key:[$elem]</span></li>";
}
else $out .= "<li><span>$key</span>".array2ul($elem)."</li>";
}
$out .= "</ul>";
return $out;
}
I think you are looking for this.
Here's a much more maintainable way to do it than to echo html...
<ul>
<?php foreach( $array as $city => $hotels ): ?>
<li><?= $city ?>
<ul>
<?php foreach( $hotels as $hotel ): ?>
<li><?= $hotel ?></li>
<?php endforeach; ?>
</ul>
</li>
<?php endforeach; ?>
</ul>
Here's another way using h2s for the cities and not nested lists
<?php foreach( $array as $city => $hotels ): ?>
<h2><?= $city ?></h2>
<ul>
<?php foreach( $hotels as $hotel ): ?>
<li><?= $hotel ?></li>
<?php endforeach; ?>
</ul>
<?php endforeach; ?>
The outputted html isn't in the prettiest format but you can fix that. It's all about whether you want pretty html or easier to read code. I'm all for easier to read code =)
Refactored acmol's funciton
/**
* Converts a multi-level array to UL list.
*/
function array2ul($array) {
$output = '<ul>';
foreach ($array as $key => $value) {
$function = is_array($value) ? __FUNCTION__ : 'htmlspecialchars';
$output .= '<li><b>' . $key . ':</b> <i>' . $function($value) . '</i></li>';
}
return $output . '</ul>';
}
Assume your data is in $array.
echo '<ul>';
foreach ($array as $city => $hotels)
{
echo "<li>$city</li>\n<ul>\n";
foreach ($hotels as $hotel)
{
echo " <li>$hotel</li>\n";
}
echo "</ul>\n\n";
}
echo '</ul>';
Haven't tested it, but I'm pretty sure it's right.
Related
I have file
animals.txt
fishes shark,tuna,salmon
birds parrot,pigeon
mammals cow,dog,cat
In every line, for example between fishes and shark is tabulation.
I wanna get this output:
<ul type="disc">
<li>fishes<br>
<ul type="disc">
<li>shark</li>
<li>tuna</li>
<li>salmon</li>
</ul>
</li>
<li>birds<br>
<ul type="disc">
<li>parrot</li>
<li>pigeon</li>
</ul>
</li>
<li>mammals<br>
<ul type="disc">
<li>cow</li>
<li>dog</li>
<li>cat</li>
</ul>
</li>
</ul>
I wrote simple code, but I don't know what can I do next, can someone help me solve it?
index.php
$file = fopen('animals.txt', 'r');
while (!feof($file)) {
$line = fgets($file);
$a = explode(" ", $line);
$b = str_replace(",", " ", $a);
$c = explode(" ", $b);
print_r($b);
}
fclose($file);
?>
If you're simply going to read that file and not write in it, maybe using file will be simpler than fopen as it creates an array of lines.
You'll want to double explode every line, once on the tabulation to separate family and animals and a second time to split animals individually.
To create a nicely structure array of families and animals, try the following and add some var_dump at different steps to see the logic:
$file = file('animals.txt');
$groupedAnimals = array();
foreach ($file as $line) {
// First explode on tabulations
$line = explode("\t", $line);
$family = $line[0];
// Then explode on commas
$animals = explode(',', $line[1]);
foreach ($animals as $animal) {
$groupedAnimals[$family][] = $animal;
}
}
The groupedAnimals array should be populated like that:
Array
(
[fishes] => Array
(
[0] => shark
[1] => tuna
[2] => salmon
)
[birds] => Array
(
[0] => parrot
[1] => pigeon
)
[mammals] => Array
(
[0] => cow
[1] => dog
[2] => cat
)
)
Once the groupedAnimals array is populated, you can simply print them the way you want, following your template:
<ul type="disc">
<?php foreach ($groupedAnimals as $family => $animals): ?>
<li>
<?php echo $family ?>
<ul>
<?php foreach ($animals as $animal): ?>
<li><?php echo $animal ?></li>
<?php endforeach ?>
</ul>
</li>
<?php endforeach ?>
</ul>
function xxAxx(){
$output='';
$file = fopen('animals.txt', 'r');
while (!feof($file))
{
$line = fgets($file);
//replace white spaces with a different delimiter
$line = preg_replace('/\s+/', '-', $line);
$line = trim($line);
// explode with your delemeter
$a = explode("-", $line);
$category = $a[0];
$categoryItems = explode(",", $a[1]);
$output .= "<li>".$category ."<br>";
$output .= "<ul type='disc'>";
foreach ($categoryItems as $item) {
$output .= '<li>'.$item.'</li>';
}
$output .= "</ul>";
$output .= "</li>";
}
fclose($file);
return $output;
}
?>
<ul type="disc">
<?php echo xxAxx(); ?>
</ul>
I'm working on a simple CMS for a pet project. I currently have a JSON string that contains a list of page ID's and Parent page ID's for a menu structure.
I want to now convert this string into a nested or hierarchical list (ordered list).
I've tried looking looping through but seem to have ended up with an overly complex range of sub classes. I'm struggling to find a suitable light-weight solution in PHP.
Here's the JSON:
**[{"id":3,"children":[{"id":4,"children":[{"id":5}]}]},{"id":6},{"id":2},{"id":4}]**
Here's the desired output:
<ol>
<li>3
<ol>
<li>4</li>
<ol>
<li>5</li>
</ol>
</ol>
</li>
<li>6</li>
<li>2</li>
<li>4</li>
</ol>
Is there anything built in to PHP that can simplify this process? Has anyone had any experience of this before?
I'm a newbie to PHP and SE. Looking forward to hearing from you.
Here's my current progress (it's not working too well)
<ol>
<?php
$json = '[{"id":3,"children":[{"id":4,"children":[{"id":5}]}]},{"id":6},{"id":2},{"id":4}]';
$decoded = json_decode($json);
$pages = $decoded;
foreach($pages as $page){
$subpages = $decoded->children;
echo "<li>".$page->id."</li>";
foreach($subpages as $subpage){
echo "<li>".$subpage->id."</li>";
}
}
?>
</ol>
You can use recursion to get deep inside the data. If the current value is an array then recursion again. Consider this example:
$json_string = '[{"id":3,"children":[{"id":4,"children":[{"id":5}]}]},{"id":6},{"id":2},{"id":4}]';
$array = json_decode($json_string, true);
function build_list($array) {
$list = '<ol>';
foreach($array as $key => $value) {
foreach($value as $key => $index) {
if(is_array($index)) {
$list .= build_list($index);
} else {
$list .= "<li>$index</li>";
}
}
}
$list .= '</ol>';
return $list;
}
echo build_list($array);
Using a function that can recursively go through your JSON, you can get the functionality you wish. Consider the following code: (this only accounts for an attribute of id as getting listed, as your desired code shows)
$json = '[{"id":3,"children":[{"id":4,"children":[{"id":5}]}]},{"id":6},{"id":2},{"id":4}]';
function createOLList($group) {
$output = (is_array($group)) ? "<ol>" : "";
foreach($group as $attr => $item) {
if(is_array($item) || is_object($item)) {
$output .= createOLList($item);
} else {
if($attr == "id") {
$output .= "<li>$item</li>";
}
}
}
$output .= (is_array($group)) ? "</ol>" : "";
return $output;
}
print(createOLList(json_decode($json)));
This will produce the following HTML output.
<ol>
<li>3</li>
<ol>
<li>4</li>
<ol>
<li>5</li>
</ol>
</ol>
<li>6</li>
<li>2</li>
<li>4</li>
</ol>
What you're looking for is called recursion, which can be done by a function calling itself.
If you solved once to list all nodes of the list in one function, you can then apply the same function for all child-lists. As then those child-lists will do the same on their children, too.
call_user_func(function ($array, $id = 'id', $list = 'children') {
$ul = function ($array) use (&$ul, $id, $list) {
echo '<ul>', !array_map(function ($child) use ($ul, $id, $list) {
echo '<li>', $child[$id], isset($child[$list]) && $ul($child[$list])
, '</li>';
}, $array), '</ul>';
};
$ul($array);
}, json_decode('[{"id":3,"children":[{"id":4,"children":[{"id":5}]}]},{"id":6},
{"id":2},{"id":4}]', TRUE));
As this example shows, the $ul function is called recursively over the list and all children. There are other solutions, but most often recursion is a simple method here to get the job done once you've wrapped your head around it.
Demo: https://eval.in/153471 ; Output (beautified):
<ul>
<li>3
<ul>
<li>4
<ul>
<li>5</li>
</ul>
</li>
</ul>
</li>
<li>6</li>
<li>2</li>
<li>4</li>
</ul>
<?php
$json_array = array();
array_push($json_array, array(
'id' => 3,
'children' => array(
'id' => 4,
'children' => array(
'id' => 5,
)
)
));
array_push($json_array, array('id' => 6));
array_push($json_array, array('id' => 2));
array_push($json_array, array('id' => 4));
//your json object
$json_object = json_encode($json_array);
//echo $json_object;
//here is where you decode your json object
$json_object_decoded = json_decode($json_object,true);
//for debug to see how your decoded json object looks as an array
/*
echo "<pre>";
print_r($json_object_decoded);
echo "</pre>";
*/
echo "<ol>";
foreach($json_object_decoded as $node){
if(isset($node['id'])){
echo "<li>" . $node['id'];
if(isset($node['children'])){
echo "<ol>";
echo "<li>" . $node['children']['id'] . "</li>";
if(isset($node['children'])){
echo "<ol>";
echo "<li>" . $node['children']['children']['id'] . "</li>";
echo "</ol>";
}
echo "</ol>";
}
echo "</li>";
}
}
echo "</ol>";
?>
I have found that i have to fix or simplify almost every of the functions above.
So here i came with something simple and working, still recursion.
function build_list($array) {
$list = '<ul>';
foreach($array as $key => $value) {
if (is_array($value)) {
$list .= "<strong>$key</strong>: " . build_list($value);
} else {
$list .= "<li><strong>$key</strong>: $value</li>";
}
}
$list .= '</ul>';
return $list;
}
build_list(json_encode($json_string),true);
I have an array I got from a mysql query
key1 key2 value
10 2 url_A
10 1 url_B
9 3 url_C
9 2 url_D
9 1 url_E
7 1 url_f
I want to put it into this format in html.
<ul class="main">
<li id="10">
<ul>
<li>url_A</li>
<li>url_B</li>
</ul>
</li>
<li id="9">
<ul>
<li>url_C</li>
<li>url_D</li>
<li>url_E</li>
</ul>
</li>
<li id="7">
<ul>
<li>url_F</li>
</ul>
</li>
</ul>
How can I use foreach() (or is there a better way) and get this done?
This is HOW I get my array now.
$result = mysql_query($sql) or die(mysql_error());
while($data = mysql_fetch_object($result)){
$Items[] = array(
'key1' => $data->pID1,
'key2' => $data->ID2,
'value' => $data->urlString,
);
}
You can build the array with two keys as well:
while ($data = mysql_fetch_object($result)) {
$Items[$data->pID1][$data->ID2] = $data->urlString;
}
And then assemble the whole thing together:
echo '<ul class="main">';
foreach ($Items as $pid => $data) {
printf('<li id="%s"><ul>', $pid);
foreach ($data as $item) {
printf('<li>%s</li>', htmlspecialchars($item, ENT_QUOTES, 'UTF-8'));
}
echo '</ul></li>';
}
echo '</ul>';
Btw, unless you're using HTML5, you shouldn't use numeric identifiers for your elements.
<?php
$arr[10][2] = "url_A";
$arr[10][1] = "url_B";
$arr[9][3] = "url_C";
$arr[9][2] = "url_D";
$arr[9][1] = "url_E";
$arr[7][1] = "url_F";
?>
<ul class="main">
<?php
foreach ($arr as $key => $val) {
echo "<li id='$key'>\n\t<ul>";
foreach ($val as $item_key => $item) {
echo "\n\t<li>$item</li>";
}
echo "\n\t</ul>\n</li>\n";
}
?>
</ul>
Consider this:
$menuItems = array (
"page1" => "1.php",
"page2" => "2.php",
"page3" => "3.php",
"page4" => "4.php",
"page5" => "5.php",
);
and now I create the menu like this:
<ul class="menu">
<?php
foreach($menuItems as $name => $url) {
echo "<li><a href='$url' class='$class'>$name</a></li>";
}
?>
</ul>
Works great. But now I need to add a class .current on the current page.
To get the current page I do this:
<?php
function curPageName() {
return substr($_SERVER["SCRIPT_NAME"],strrpos($_SERVER["SCRIPT_NAME"],"/")+1);
}
$curpage = curPageName();
?>
And it also works great.
SO I guess the question is how do I assign $curpage to the ... current page? :)
Thank you.
Alex
<ul class="menu">
<?php
foreach($menuItems as $name => $url) {
if ($url === $curpage){
$class.=' .current';
}
echo "<li><a href='$url' class='$class'>$name</a></li>";
}
?>
</ul>
Easy, inside your loop, check if $url == $curpage, and append appropriately.
Example:
<?php
$menuItems = array(
"page1" => "1.php",
"page2" => "2.php",
"page3" => "3.php",
"page4" => "4.php",
"page5" => "5.php",
);
$current_item = "2.php"; //Assume we got this from the function
?>
<ul class="menu">
<?php
foreach ($menuItems as $name => $url) {
echo "<li><a href='$url'";
if ($url == $current_item) {
echo " class='current'";
}
echo ">$name</a></li>\n";
}
?>
</ul>
<ul class="menu">
<?php
foreach($menuItems as $name => $url) {
$class = 'default';
if (curPageName() == $name) {
$class.='.current';
}
echo "<li><a href='$url' class='$class'>$name</a></li>";
}
?>
</ul>
So I made it work with your help! Thanks guys.
Special thanks for Adel - although you had a mistake there I fixed it like this:
foreach($menuItems as $name => $url) {
$class = 'default';
if (curPageName() == $url) {
$class.=' \. current';
}
echo "<li><a href='$url' class='$class'>$name</a></li>";
}
Awesome! Thanks again!
<?php
$menuItems = array(
'page1' => '1.php',
'page2' => '2.php',
'page3' => '3.php',
'page4' => '4.php',
'page5' => '5.php',
);
$current_page = curPageName();
?>
<ul class="menu">
<?php
foreach ($menuItems as $name => $url) {
?>
<li><a href="<?php=$url?>"
<?php
if ($url == $current_page) {
?>
class="current"
<?php
}
?>
><?php=$name?></a></li>
<?php
}
?>
</ul>
Why use the curPageName () at each iteration?
You can use a ternary syntax to solve your problem. It consists in this syntax:
(if condition ? true : false)
So we can use this way on your answer comparing the curPageName with the url inside the foreach loop.
$url == curPageName() ? 'current' : 'notCurrent'
Now you just need to use this in your favor.
I like the syntax of printf. So the code is more clean. Try this:
<?php
/**
* curPageName() is defined in question
* my_links() is a shortcut to array defined in question
*/
$template = "<li%s>%s</li>";
$links = my_links();
$current = curPageName();
print '<ul class="menu">';
foreach ($likns as $name => $url) {
$class = $current == $url ? ' class="current"' : '';
printf($template, $class, $url, $name);
}
print '</ul>';
Each %s item in $template will be changed by sequential variable. So, if you need to change the template the code is clean and easyest to give a maintance.
Or, if you want another easiest template way, use the php template syntax. Note the use of : after the foreach statement and the use of endforeach. You can see that I am using the short code of echo <?=$var?> that is more compreensible than <?php echo $var ?>.
<?php
/**
* curPageName() is defined in question
* my_links() is a shortcut to array defined in question
*/
$links = my_links();
$current = curPageName();
?>
<ul class="menu">
<?php foreach ($links as $name => $url): ?>
<li<?=($current == $url ? ' class="current"' : '')?>>
<?=$name?>
</li>
<?php endforeach ?>
</ul>
I am trying to make a php navbar sort of thing. I have the html code and what I want to do is to use a php dictionary ("Home"=>"http://www.domain.com/") and turn it into html code.
<ul>
<?php foreach ($links as $title => $url): ?>
<li><?php echo htmlentities($title); ?></li>
<?php endforeach; ?>
</ul>
foreach($arr as $key=>$value) {
// your code here
}
I have no idea how you want to make your navbar, but with any knowledge of HTML you should be able to go from here.
foreach (dict as $key => $value){
echo "<a href='$value'>$key</a>";
}
Fastest
<?php
foreach($array as $name => $link){
echo '',$name,'\n';
}
?>
Easier to read and understand but slower
<?php
foreach($array as $name => $link){
echo "<a href='$link'>$name</a>\n";
}
?>
I don't know if i understand the question but you can use an hash like this:
<?php
$navBar = array(
"Home" => "http://www.domain.com/",
"Info" => "http://www.domain.com/info/",
);
foreach($navBar as $key => $val){
echo "<li>$key => $val<li>";
}
?>