//code from Telerik MVC Extensions using System.Text; using System.Xml; using Microsoft.AspNetCore.Routing; using Nop.Core.Infrastructure; using Nop.Services.Localization; using Nop.Services.Security; namespace Nop.Web.Framework.Menu; /// /// XML sitemap /// public partial class XmlSiteMap : IXmlSiteMap { #region Fields protected readonly ILocalizationService _localizationService; protected readonly INopFileProvider _fileProvider; protected readonly IPermissionService _permissionService; private static readonly char[] _separator = [',']; #endregion #region Ctor /// /// Ctor /// public XmlSiteMap(ILocalizationService localizationService, INopFileProvider fileProvider, IPermissionService permissionService) { _localizationService = localizationService; _fileProvider = fileProvider; _permissionService = permissionService; RootNode = new SiteMapNode(); } #endregion #region Utilities /// A task that represents the asynchronous operation protected virtual async Task IterateAsync(SiteMapNode siteMapNode, XmlNode xmlNode) { await PopulateNodeAsync(siteMapNode, xmlNode); foreach (XmlNode xmlChildNode in xmlNode.ChildNodes) if (xmlChildNode.LocalName.Equals("siteMapNode", StringComparison.InvariantCultureIgnoreCase)) { var siteMapChildNode = new SiteMapNode(); siteMapNode.ChildNodes.Add(siteMapChildNode); await IterateAsync(siteMapChildNode, xmlChildNode); } } /// A task that represents the asynchronous operation protected virtual async Task PopulateNodeAsync(SiteMapNode siteMapNode, XmlNode xmlNode) { //system name siteMapNode.SystemName = GetStringValueFromAttribute(xmlNode, "SystemName"); //title var nopResource = GetStringValueFromAttribute(xmlNode, "nopResource"); siteMapNode.Title = await _localizationService.GetResourceAsync(nopResource); //routes, url var controllerName = GetStringValueFromAttribute(xmlNode, "controller"); var actionName = GetStringValueFromAttribute(xmlNode, "action"); var url = GetStringValueFromAttribute(xmlNode, "url"); if (!string.IsNullOrEmpty(controllerName) && !string.IsNullOrEmpty(actionName)) { siteMapNode.ControllerName = controllerName; siteMapNode.ActionName = actionName; //apply admin area as described here - https://www.nopcommerce.com/boards/topic/20478/broken-menus-in-admin-area-whilst-trying-to-make-a-plugin-admin-page siteMapNode.RouteValues = new RouteValueDictionary { { "area", AreaNames.ADMIN } }; } else if (!string.IsNullOrEmpty(url)) siteMapNode.Url = url; //image URL siteMapNode.IconClass = GetStringValueFromAttribute(xmlNode, "IconClass"); //permission name var permissionNames = GetStringValueFromAttribute(xmlNode, "PermissionNames"); if (!string.IsNullOrEmpty(permissionNames)) siteMapNode.Visible = await permissionNames.Split(_separator, StringSplitOptions.RemoveEmptyEntries) .AnyAwaitAsync(async permissionName => await _permissionService.AuthorizeAsync(permissionName.Trim())); else siteMapNode.Visible = true; // Open URL in new tab var openUrlInNewTabValue = GetStringValueFromAttribute(xmlNode, "OpenUrlInNewTab"); if (!string.IsNullOrWhiteSpace(openUrlInNewTabValue) && bool.TryParse(openUrlInNewTabValue, out var booleanResult)) siteMapNode.OpenUrlInNewTab = booleanResult; } protected static string GetStringValueFromAttribute(XmlNode node, string attributeName) { string value = null; if (node.Attributes != null && node.Attributes.Count > 0) { var attribute = node.Attributes[attributeName]; if (attribute != null) value = attribute.Value; } return value; } #endregion #region Methods /// /// Load sitemap /// /// Filepath to load a sitemap /// A task that represents the asynchronous operation public virtual async Task LoadFromAsync(string physicalPath) { var filePath = _fileProvider.MapPath(physicalPath); var content = await _fileProvider.ReadAllTextAsync(filePath, Encoding.UTF8); if (!string.IsNullOrEmpty(content)) { var doc = new XmlDocument(); using (var sr = new StringReader(content)) { using var xr = XmlReader.Create(sr, new XmlReaderSettings { CloseInput = true, IgnoreWhitespace = true, IgnoreComments = true, IgnoreProcessingInstructions = true }); doc.Load(xr); } if ((doc.DocumentElement != null) && doc.HasChildNodes) { var xmlRootNode = doc.DocumentElement.FirstChild; await IterateAsync(RootNode, xmlRootNode); } } } #endregion #region Properties /// /// Root node /// public SiteMapNode RootNode { get; set; } #endregion }