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
)
)
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 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);
I am rendering navigation from a 2 dimensional array, using lists, as shown:
<ul> <li>parent
<ul> <li>level 1</li> <li>level 1
<ul> <li>level 3</li> </ul>
</li> </ul>
<li> </ul>
</li> </ul>
Anyway to close the <li> and </ul> correctly I find I need some data from the next array in the foreach sequence. How can I retrieve this?
Although I've had choppy results with them in the past you can use the below functions to move the current array pointer.
prev() - http://www.php.net/manual/en/function.prev.php
next() - http://www.php.net/manual/en/function.next.php
end() - http://www.php.net/manual/en/function.end.php
reset() - http://www.php.net/manual/en/function.reset.php
Hopefully that'll help.
Here's a solution:
$arr = array(1,2,3,4,5);
foreach ($arr as $foo) {
if (empty($isrewind)) {
reset($arr);
$isrewind = true;
}
echo "node: $foo\n";
$copy = $arr; // make a copy of the array
$next = next($copy);
echo "next: $next\n";
$copy = $arr; // make a copy of the array
$prev = prev($copy);
echo "prev: $prev\n";
next($arr); // don't forget to advance the pointer on the original array
}
I've demonstrated the prev bit just for the example. You can easily do that without prev() by saving the element at the end of each iteration.
The if empty bit resets the array pointer to the beginning, because foreach will advance the pointer once when it makes a copy of the array.
The above example yields:
node: 1
next: 2
prev:
node: 2
next: 3
prev: 1
node: 3
next: 4
prev: 2
node: 4
next: 5
prev: 3
node: 5
next:
prev: 4
If you have to do something like this though, there might be a better way just by rearranging your data structure (hard to tell without code).
IHMO it's not possible with a simple foreach loop on an array that has non-numeric indexes. But you can extend the SPL class CachingIterator to wrap your array in this. In your extended class you can implement methods to return the previous and next index/value without advancing the internal element pointer.
If you have an array with numeric indexes use a for loop instead of a foreach. You can then use $i+1 and $i-1 to look at different array indexes than the current index.
Not sure if this is what he asking for, but here's my shot
$list = array (
'Home page' => null,
'Articles' => array (
'Diving' => null,
'Skydiving' => null,
'Stackoverflowing' => null,
),
'Nobody cares' => array (
'Hey' => null,
'It is just a test' => null,
),
);
function render_menu ($list)
{
echo "<ul>\n";
foreach ($y = new RecursiveArrayIterator ($list, RecursiveIteratorIterator::SELF_FIRST) as $key => $item)
{
if ($y->hasChildren ())
{
echo "<li>$key\n";
render_menu ($item);
echo "</li>\n";
}
else
{
echo "<li>$key</li>\n";
}
}
echo "</ul>\n";
}
render_menu ($list);
Found the answer staring me in the face. Retrieved the arrays I need like this:
foreach ($tree as $key => $link) {
$level = $link['level'];
$next_key = $key+1;
$prev_key = $key-1;
$next_array = $tree[$next_key];
$prev_array = $tree[$prev_key];
And then I could test the level property (indicating deph inside the navigation tree) with a buch of if statements to correctly insert the closing markup.
Messy code and I'm not proud of it, but it works!
Quite angry with myself for not seeing it before.
I assume you are using php. I dont think it's possible, you must know the index of element and index the array. Sth like this:
$i=0;
foreach ($array as $element){
echo $element;
//do sth with $array[$i+1];
//do sth with $array[$i-1];
$i++;
}
Have no other clue
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>';