I have been trying to build a child/parent navigation for a little while now using PHP (I'm from a .net background) and I can't get close to the desired results. I am loading my data from an XML file using SimpleXML
successfully but I am trying to work out how I can map that into arrays or variables so I can write it out.
<Categories>
<Category>
<ID>1</ID>
<Title>Days</Title>
<Description />
<ParentID />
<Meta />
</Category>
<Category>
<ID>2</ID>
<Title>Monday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>3</ID>
<Title>Tuesday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>4</ID>
<Title>Wednesday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>5</ID>
<Title>Thursday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>6</ID>
<Title>Friday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>7</ID>
<Title>Saturday</Title>
<Description />
<ParentID/>
<Meta />
</Category>
<Category>
<ID>8</ID>
<Title>Sunday</Title>
<Description />
<ParentID/>
<Meta />
</Category>
</Categories>
foreach($categories as $category) {
if ($category->ParentID != "")
{
echo "<li><a href=index.php?Cat=$category->ID>$category->Title</a></li>";
echo "<ul>";
foreach($categories as $subcategory) {
if ($subcategory->ParentID == $category->ID)
{
echo "<li><a href=index.php?Cat=$subcategory->ID>$subcategory->Title</a></li>";
}
}
echo "</ul>";
}
else
{
echo "<li><a href=index.php?Cat=$category->ID>$category->Title</a></li>";
}
}
echo "</ul>";
So my desired output would be something like this:
<ul id="p7menubar">
<li><a class="trigger" href="#">Days</a>
<ul>
<li><a href="#">Monday</a></li>
<li><a href="#">Tuesday</a></li>
<li><a href="#">Wednesday</a></li>
<li><a href="#">Thursday</a></li>
<li><a href="#">Friday</a></li>
</ul>
</li>
<li><a href="index.htm">Saturday</a><开发者_如何学运维/li>
<li><a href="index.htm">Sunday</a></li>
</ul>
I decided to bash on this code for the last 20 minutes. You need two instances of the list otherwise you are changing the index mid iteration. My advice is the top area:
if (file_exists('cats.xml')) {
$xml = simplexml_load_file('cats.xml');
$categories = simplexml_load_file('cats.xml');
} else {
exit('Failed to open cats.xml.');
}
echo "<ul>";
foreach($categories as $category) {
if (!(int)$category->ParentID > 0){
// if the parentid is not set this is a root element and we want to print it and
// it's children.
categorylist($category, $xml);
}
}
echo "</ul>";
function categorylist($current, $list){
// so echo the item list and link opener, but not the closer
echo "<li><a href='index.php?Cat=$current->ID'>$current->Title</a>";
// we need to count the number of children
$count = 0;
foreach($list as $item){
// just iterate through the list for a match
if ((int)$item->ParentID == (int)$current->ID){
if($count == 0){
// if its the first match open the new child list tag
echo "<ul>";
}
// print the child link and item and iterate the counter
echo "<li><a href=index.php?Cat=$item->ID>$item->Title</a></li>";
$count = $count + 1;
}
}
if($count > 0){
// if their were children print the close of the list
echo "</ul>";
}
// now close the list item.
echo "</li>";
}
this gets the output you describe but no more, though it hints at the method you would use to create a recursive version. Of course cats.xml contains your xml content above.
If your data is going to be tree-structured (which it seems to be — each parent has multiple children), why not store them in an XML like this?
<?xml version="1.0"?>
<Categories>
<Category>
<Title>Days</Title>
<Description/>
<Meta/>
<Categories>
<Category>
<Title>Monday</Title>
<Description/>
<Meta/>
</Category>
<Category>
<Title>Tuesday</Title>
<Description/>
<Meta/>
</Category>
<Category>
<Title>Wednesday</Title>
<Description/>
<Meta/>
</Category>
<Category>
<Title>Thursday</Title>
<Description/>
<Meta/>
</Category>
<Category>
<Title>Friday</Title>
<Description/>
<Meta/>
</Category>
</Categories>
</Category>
<Category>
<Title>Saturday</Title>
<Description/>
<Meta/>
</Category>
<Category>
<Title>Sunday</Title>
<Description/>
<Meta/>
</Category>
</Categories>
This way the transformation is far simpler — you can use a very basic XSLT transform.
Of course a lot of optimizing needed but that's do the trick
$str = <<<XML
<?xml version='1.0'?>
<Categories>
<Category>
<ID>1</ID>
<Title>Days</Title>
<Description />
<ParentID />
<Meta />
</Category>
<Category>
<ID>2</ID>
<Title>Monday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>3</ID>
<Title>Tuesday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>4</ID>
<Title>Wednesday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>5</ID>
<Title>Thursday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>6</ID>
<Title>Friday</Title>
<Description />
<ParentID>1</ParentID>
<Meta />
</Category>
<Category>
<ID>7</ID>
<Title>Saturday</Title>
<Description />
<ParentID/>
<Meta />
</Category>
<Category>
<ID>8</ID>
<Title>Sunday</Title>
<Description />
<ParentID/>
<Meta />
</Category>
</Categories>
XML;
$xml = simplexml_load_string($str);
$htmllist = '<ul id="p7menubar">';
foreach($xml->Category as $category)
{
switch($category->ID)
{
case '1':
$htmllist .= '<li><a class="trigger" href="#">' . $category->Title . '</a><ul>';
break;
case '2':
case '3':
case '4':
case '5':
case '6':
$htmllist .= '<li><a href="#">' . $category->Title . '</a></li>';
break;
case '7':
$htmllist .= '</ul><li><a href="index.htm">' . $category->Title . '</a></li>';
break;
case '8':
$htmllist .= '</ul><li><a href="index.htm">' . $category->Title . '</a></li></ul>';
break;
}
}
echo $htmllist;
?>
Some optimization tips:
- If you can modify you XML source, you could insert you href attributes, classes or any other variables for cleaner code at the end.
- You can even want to create nested XML nodes so your ul almost can take place in the XML itself
精彩评论