Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of XML attribute inheritance #134

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 52 additions & 30 deletions src/MvcSiteMapProvider/MvcSiteMapProvider/DefaultSiteMapProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ namespace MvcSiteMapProvider
public class DefaultSiteMapProvider
: StaticSiteMapProvider
{
#region Attribute names

protected const string AttributesToInheritKey = "attributesToInherit";

#endregion

#region Private

private readonly char[] configValueSeparators = new[] { ';', ',' };

protected const string RootName = "mvcSiteMap";
protected const string NodeName = "mvcSiteMapNode";
protected readonly XNamespace ns = "http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0";
Expand All @@ -42,6 +50,8 @@ public class DefaultSiteMapProvider
protected List<string> excludeAssembliesForScan = new List<string>();
protected List<string> includeAssembliesForScan = new List<string>();
protected List<string> attributesToIgnore = new List<string>();
protected string[] attributesToInherit = new string[0];

#endregion

#region Properties
Expand Down Expand Up @@ -296,6 +306,12 @@ public override void Initialize(string name, NameValueCollection attributes)
}
}

// Which attributes in the sitemap XML should be inherited from parent nodes?
if(!string.IsNullOrEmpty(attributes[AttributesToInheritKey]))
{
attributesToInherit = attributes[AttributesToInheritKey].Split(configValueSeparators);
}

// Is a node key generator given?
if (!string.IsNullOrEmpty(attributes["nodeKeyGenerator"]))
{
Expand Down Expand Up @@ -1442,35 +1458,17 @@ protected MvcSiteMapNode GetSiteMapNodeFromXmlElement(XElement node, SiteMapNode
siteMapNode.ResourceKey = implicitResourceKey;

// Create a route data dictionary
IDictionary<string, object> routeValues = new Dictionary<string, object>();
AttributesToRouteValues(node, siteMapNode, routeValues);
siteMapNode.RouteValues = new Dictionary<string, object>();
AttributesToRouteValues(node, siteMapNode, siteMapNode.RouteValues);

// Inherit area and controller from parent
if (parentMvcNode != null)
{
if (siteMapNode["area"] == null)
{
siteMapNode["area"] = parentMvcNode.Area;
routeValues.Add("area", parentMvcNode.Area);
}
if (node.GetAttributeValue("controller") == "")
{
siteMapNode["controller"] = parentMvcNode.Controller;
routeValues.Add("controller", parentMvcNode.Controller);
}
var action = "action";
if (node.GetAttributeValue(action) == String.Empty)
{
siteMapNode[action] = parentMvcNode.Action;
routeValues.Add(action, parentMvcNode.Action);
}
}
// Load inherited attributes
LoadInheritedAttribute("area", node, siteMapNode, parentMvcNode, defaultValue: string.Empty, isRouteValue: true);
LoadInheritedAttribute("controller", node, siteMapNode, parentMvcNode, isRouteValue: true);
LoadInheritedAttribute("action", node, siteMapNode, parentMvcNode, isRouteValue: true);

// Add defaults for area
if (!routeValues.ContainsKey("area"))
foreach(var attributeName in attributesToInherit)
{
siteMapNode["area"] = "";
routeValues.Add("area", "");
LoadInheritedAttribute(attributeName, node, siteMapNode, parentMvcNode);
}

// Add defaults for SiteMapNodeUrlResolver
Expand All @@ -1497,13 +1495,10 @@ protected MvcSiteMapNode GetSiteMapNodeFromXmlElement(XElement node, SiteMapNode
var item = inheritedRouteParameter.Trim();
if (parentMvcNode != null && parentMvcNode.RouteValues.ContainsKey(item))
{
routeValues[item] = parentMvcNode.RouteValues[item];
siteMapNode.RouteValues[item] = parentMvcNode.RouteValues[item];
}
}

// Add route values to sitemap node
siteMapNode.RouteValues = routeValues;

// Add node's route defaults
var httpContext = new HttpContextWrapper(HttpContext.Current);
RouteData routeData = siteMapNode.GetRouteData(httpContext);
Expand Down Expand Up @@ -1791,6 +1786,33 @@ protected void DecodeExternalUrl(SiteMapNode node)
node.Url = HttpContext.Current.Server.UrlDecode(node.Url);
}

/// <summary>
/// Get the attribute value from current node or from the parent nodes
/// </summary>
/// <param name="attributeName">Name of the attribute</param>
/// <param name="xmlNode">Xml node</param>
/// <param name="siteMapNode">MvcSiteMapNode to set the attribute to.</param>
/// <param name="parentNode">Parent MvcSiteMapNode</param>
/// <param name="defaultValue">Default attribute value</param>
/// <param name="isRouteValue">If this flag is set to "true", than the attribute value will also be added to routeValues</param>
private void LoadInheritedAttribute(string attributeName, XElement xmlNode, MvcSiteMapNode siteMapNode, MvcSiteMapNode parentNode, string defaultValue = null, bool isRouteValue = false)
{
var value = xmlNode.GetAttributeValue(attributeName);
var currentNode = parentNode;

while(currentNode != null && string.IsNullOrEmpty(value))
{
value = currentNode[attributeName];
currentNode = currentNode.ParentNode as MvcSiteMapNode;
}

siteMapNode[attributeName] = value ?? defaultValue;
if(isRouteValue)
{
siteMapNode.RouteValues[attributeName] = value ?? defaultValue;
}
}

#endregion
}
}