Add CSS class to parent node if child node is selected
I have a recusive-method that creates an unordered list from an XML document. To check which node I am placed on, I use a query string to map the URL in the XML document.
I need to add the 'current' class to the parent node if I am placed in its child node.
Like this:
MenuItem 1
MenuItem 2 [class current]
MenuItem 3 [class current] (selected node)
MenuItem 4
My XML document looks like this:
<MenuItem Name="MenuItem 1" Url="MenuItem1.aspx"/>
<MenuItem Name="MenuItem 2" Url="MenuItem2.aspx">
<MenuItem Name="MenuItem 3" Url="MenuItem3.aspx" />
</MenuItem>
<MenuItem Name="MenuItem4" Url="MenuItem4.asp" />
And my current code looks like this:
foreach (XmlNode item in menuitems)
{
if (HttpContext.Current.Request.Url.AbsolutePath.ToLower() == item.Attributes["Url"].Value.ToLower())
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "current");
}
writer.RenderBeginTag(HtmlTextWriterTag.Li);
// And so on...
}
So, I need some kind of function to find this node and put the class on this node.
If you need more code, information or anything else - say so! :-)
Thanks!
a source to share
Thanks for answers. But I solved my problem. You guys get your effort for it.
Here is my solution:
System.Collections.Hashtable ht = new System.Collections.Hashtable();
ht.Add("Url", HttpContext.Current.Request.Url.AbsolutePath.ToLower());
XmlNode currentpage = Core.FindChildNode(item, "MenuItem", ht);
if (HttpContext.Current.Request.RawUrl.ToLower() == item.Attributes["Url"].Value.ToLower() || currentpage != null)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "current");
}
This is my FindChildNode method
public static XmlNode FindChildNode(XmlNode parent, string name, System.Collections.Hashtable keyvaluecollection)
{
if (parent.NodeType != XmlNodeType.Element) return null;
XmlElement el = (XmlElement)parent;
XmlNodeList nodes = el.GetElementsByTagName(name);
foreach (XmlNode node in nodes)
{
if (node.NodeType == XmlNodeType.Element)
{
bool found = false;
foreach (string key in keyvaluecollection.Keys)
{
if (node.Attributes[key] != null && node.Attributes[key].Value == (string)keyvaluecollection[key])
{
found = true;
}
else
{
found = false;
break;
}
}
if (found) return node;
}
}
return null;
}
It seems to work like a charm! :-)
a source to share
It's not a particularly elegant solution, but if I understand the problem correctly, you can create a method to check if a child node is selected:
private static bool IsChildSelected(XmlNode item)
{
foreach(XmlNode child in item.ChildNodes)
{
if(HttpContext.Current.Request.Url.AbsolutePath.ToLower() == child.Attributes["Url"].Value.ToLower())
{
return true;
}
}
return false;
}
and check it out when you iterate over the nodes:
foreach(XmlNode item in menuitems)
{
if(HttpContext.Current.Request.Url.AbsolutePath.ToLower() == item.Attributes["Url"].Value.ToLower()
|| IsChildSelected(item))
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "current");
}
writer.RenderBeginTag(HtmlTextWriterTag.Li);
}
a source to share
I tried to create a small Unit test to demonstrate my idea. basically you get the selected node and then you traverse its parents recursively.
private bool IsParentOf(XmlNode parentNode, XmlNode node)
{
if (node.ParentNode == null) return false;
return node.ParentNode == parentNode || IsParentOf(parentNode, node.ParentNode);
}
[TestMethod]
public void TestMethod1()
{
string xml =
@"
<MenuItem Name=""MenuItem 1"" Url=""MenuItem1.aspx""/>
<MenuItem Name=""MenuItem 2"" Url=""MenuItem2.aspx"">
<MenuItem Name=""MenuItem 3"" Url=""MenuItem3.aspx"" />
</MenuItem>
<MenuItem Name=""MenuItem4"" Url=""MenuItem4.asp"" />";
string url = "MenuItem3.aspx";
XmlDocument doc = new XmlDocument();
doc.LoadXml("<MenuItems>" + xml + "</MenuItems>");
var xPathFormat = "//MenuItem[@Url='{0}']";
var currentNode = doc.SelectSingleNode(string.Format(xPathFormat, url));
var menuItem1 = doc.SelectSingleNode(string.Format(xPathFormat, "MenuItem1.aspx"));
Assert.IsFalse(IsParentOf(menuItem1, currentNode));
var menuItem2 = doc.SelectSingleNode(string.Format(xPathFormat, "MenuItem2.aspx"));
Assert.IsTrue(IsParentOf(menuItem2, currentNode));
}
a source to share