Php string to multilevel lists HTML - php

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>

Related

Get tags with class name using XPATH

Below is my xml
<div class="image">
<img src="">
<div class="image-text"><p class="border_style">work </p></div>
</div>
I want to get all the contents inside class="image-text"
output
<p class="border_style">work </p>
how can I do this using XPath? or any other way?
I've tried this,
$image->xpath("*[#class='image-text']") but didn't work.
Please advice
New
$i = 0;
$imageXmlParts = $xmlobject->xpath("//div[#class='block-image']");
$imageText = $xmlobject->xpath("//*[#class='block-image-text']");
foreach ( $imageText as $image ){
echo $image->asXML().PHP_EOL;
$out = "";
foreach ( $image->children() as $content ) {
$out .= $content->asXML();
}
echo $out.PHP_EOL;
}
foreach ($imageXmlParts as $imageXml) {
$i++;
$imagedata = array(
'template' => (string) $this->template,
'src' => (string) $imageXml->img['src'],
'imagetext' => ///need to add here
));
}
Using the XPath you have should get you the following...
$imageText = $image->xpath("//*[#class='image-text']");
echo $imageText[0]->asXML().PHP_EOL;
gives...
<div class="image-text">
<p class="border_style">work </p>
</div>
which includes the node itself. Using [0] gives the first item that matches the XPath expression as xpath() always returns an array of matches.
If you want JUST the content, then you will have to build it up from the child nodes of the one found...
$out = "";
foreach ( $imageText[0]->children() as $content ) {
$out .= $content->asXML();
}
echo $out;
which just gives...
<p class="border_style">work </p>
Update:
To add this into the code you have, I've restructured it a bit so that it starts off looking for the outer tag (I think with class called block-image) and then it loops over that. Then it uses XPath within this element to find the text for it.
$imageXmlParts = $image->xpath("//*[#class='block-image']");
$imagedata = array();
foreach ( $imageXmlParts as $imageXml ){
$text = $imageXml->xpath("descendant::div[#class='block-image-text']");
$out = "";
foreach ( $text[0]->children() as $content ) {
$out .= $content->asXML();
}
if ( $out == "" ) {
$out = (string)$text[0];
}
$imagedata[] = array(
'template' => (string) $this->template,
'src' => (string) $imageXml->img['src'],
'imagetext' => $out
);
}
Final update:
It may be easier to just extract the XML from the node and then remove the tags -
$out = $text[0]->asXML();
gives you...
<div class="block-image-text">
<p class="border_style">work </p>
aaaa
</div>
You may be able to use regular expression to remove the tags, but I've gone for the simple replace and chop the last part of the string off method...
foreach ( $imageXmlParts as $imageXml ){
$text = $imageXml->xpath("descendant::div[#class='block-image-text']");
$out = $text[0]->asXML();
$out = str_replace('<div class="block-image-text">', '', $out);
$out = substr($out, 0, -6);
$imagedata[] = array(
'template' => (string) '$this->template',
'src' => (string) $imageXml->img['src'],
'imagetext' => $out
);
}

PHP Nested list from a text file

I have textfile "animals.txt" which looks like:
mammals cat, fox, horse
birds parrot, eagle
reptiles snake, crocodile
Columns are separated with \t and ,.
How can I display it as nested list looking like this:
<ul>
<li>mammals
<ul>
<li>cat</li>
<li>fox</li>
<li>horse</li>
</ul>
</li>
<li>birds
<ul>
<li>parrot</li>
<li>eagle</li>
</ul>
</li>
<li>reptiles
<ul>
<li>snake</li>
<li>crocodile</li>
</ul>
</li>
</ul>
What I have now:
$data = file_get_contents('animals.txt');
$array = explode("\t", $data);
foreach ($array as $line) {
echo "<li>$line</li>";
}
This will work. Exploding each line and then printing the corresponding ul's and li's:
$file = file('animals.txt');
print '<ul>';
foreach ($file as $line) {
// 1) exploding by "\t" and then again by ","
$values = explode("\t", $line);
$list = explode(',', $values[1]);
// 2) show the first name in the line
print '<li>';
print $values[0];
print '<ul>';
// 3) followed by a nested ul containing the comma-separated values
foreach ($list as $sub_item) {
print '<li>' . $sub_item . '</li>';
}
print '</ul>';
print '</li>';
}
print '</ul>';
This will work. The first step is to separate values that are tab delimited(mammals cat, fox, horse) and second step(foreach loop) is to get comma delimited values(cat, fox, horse). Finally we are printing individual values in a list(cat fox etc).
echo "<ul>";
$array = explode("\t", $data);
echo "<li>".$array[0];
foreach ($array[1] as $line) {
$values = explode(",",$line)
echo "<ul>"
foreach ($values as $val) {
echo "<li>$val</li>";
}
echo "<.ul>"
}
echo "</li>";
echo "</ul>";

Format my JSON string into an <ol> ordered list in PHP

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);

PHP array Finding values based on two keys

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>

PHP Array to List

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.

Categories