I'd build upon @sepp2k's modification by separating the concerns of 1) getting the link data, 2) building the links, 3) combining links into a bulleted list, and 4) adding the bullets to navList as follows:
private void LoadNavigation()
{
Uri urlPrefix = new Uri("http://mysite.com");
string xmlFilePath = ConfigurationManager.AppSettings["NavigationUrl"].ToString();
XmlDocument doc = new XmlDocument();
doc.Load(xmlFilePath);
XmlNodeList navigationItems = doc.DocumentElement.FirstChild.ChildNodes;
var links = navigationItems
.Cast<XmlNode>()
.Select(x => new
{
FullUrl = new Uri(urlPrefix, x.Attributes.GetNamedItem("url").Value) ,
Title = x.Attributes.GetNamedItem("title").Value
})
.Select(x => String.Format("<a href=\"{0}\">{1}</a>", x.FullUrl, x.Title))
.ToArray();
var bulletedLinks = "<li>" + String.Join("|</li><li>", links) + "</li>";
navList.InnerHtml += bulletedLinks;
}
Next I'd separate the concerns of 1) getting the xmlFilePath from the ConfigurationManager, and 2) loading the navigations items, from the process of updating navList. I'd also pass in the urlPrefix string or fetch it from an application configuration setting instead of hard coding it.
private string GetNavigationUrlXmlFilePath()
{
string xmlFilePath = ConfigurationManager.AppSettings["NavigationUrl"].ToString();
return xmlFilePath;
}
private IEnumerable<XmlNode> LoadNavigationItems()
{
var xmlFilePath = GetNavigationUrlXmlFilePath();
XmlDocument doc = new XmlDocument();
doc.Load(xmlFilePath);
XmlNodeList navigationItems = doc.DocumentElement.FirstChild.ChildNodes;
return navigationItems.Cast<XmlNode>();
}
private void LoadNavigation(Uri urlPrefix)
{
var links = LoadNavigationItems()
.Select(x => new
{
FullUrl = new Uri(urlPrefix, x.Attributes.GetNamedItem("url").Value) ,
Title = x.Attributes.GetNamedItem("title").Value
})
.Select(x => String.Format("<a href=\"{0}\">{1}</a>", x.FullUrl, x.Title))
.ToArray();
var bulletedLinks = "<li>" + String.Join("|</li><li>", links) + "</li>";
navList.InnerHtml += bulletedLinks;
}
I'd also pull "NavigationUrl" out to a single location so I wouldn't have to change a bunch of code when I want to change the key name.
public static class ApplicationConfigurationSettingsKeys
{
public static class MySite
{
public static readonly string NavigationUrl = "NavigationUrl";
}
}
Then I'd put GetNavigationUrlXmlFilePath and LoadNavigationItems behind interfaces so that they can be tested independently and LoadNavigation can be tested without having to go to the disk.
public interface IApplicationConfigurationSettingsProvider
{
string GetSetting(string key);
}
public class ApplicationConfigurationSettingsProvider : IApplicationConfigurationSettingsProvider
{
public string GetSetting(string key)
{
return ConfigurationManager.AppSettings[key].ToString();
}
}
public interface INavigationLoader
{
IEnumerable<XmlNode> LoadNavigationItems();
}
public class NavigationLoader : INavigationLoader
{
private readonly IApplicationConfigurationSettingsProvider _applicationConfigurationSettingsProvider;
public NavigationLoader(IApplicationConfigurationSettingsProvider applicationConfigurationSettingsProvider)
{
_applicationConfigurationSettingsProvider = applicationConfigurationSettingsProvider;
}
public IEnumerable<XmlNode> LoadNavigationItems()
{
var xmlFilePath = _applicationConfigurationSettingsProvider
.GetSetting(ApplicationConfigurationSettingsKeys.MySite.NavigationUrl);
var doc = new XmlDocument();
doc.Load(xmlFilePath);
var navigationItems = doc.DocumentElement.FirstChild.ChildNodes;
return navigationItems.Cast<XmlNode>();
}
}
leaving:
private readonly INavigationLoader _navigationLoader;
private void LoadNavigation(Uri urlPrefix)
{
var links = _navigationLoader.LoadNavigationItems()
.Select(x => new
{
FullUrl = new Uri(urlPrefix, x.Attributes.GetNamedItem("url").Value) ,
Title = x.Attributes.GetNamedItem("title").Value
})
.Select(x => String.Format("<a href=\"{0}\">{1}</a>", x.FullUrl, x.Title))
.ToArray();
var bulletedLinks = "<li>" + String.Join("|</li><li>", links) + "</li>";
navList.InnerHtml += bulletedLinks;
}
Next I'd pull the conversion of XmlNode data to an HTML link out where it can be tested independently, possibly to an extension method:
public static class XmlNodeExtensions
{
public static string ToHtmlLink(this XmlNode node, Uri urlPrefix)
{
var fullUrl = new Uri(urlPrefix, node.Attributes.GetNamedItem("url").Value);
var title = node.Attributes.GetNamedItem("title").Value;
return String.Format("<a href=\"{0}\">{1}</a>", fullUrl, title);
}
}
leaving:
private void LoadNavigation(Uri urlPrefix)
{
var links = _navigationLoader.LoadNavigationItems()
.Select(x => x.ToHtmlLink(urlPrefix))
.ToArray();
var bulletedLinks = "<li>" + String.Join("|</li><li>", links) + "</li>";
navList.InnerHtml += bulletedLinks;
}
Finally, I'd pull out another method, possibly an extension, for building the bulleted list
public static class StringExtensions
{
public static string ToHtmlBullets(this IEnumerable<string> items, string suffix)
{
var bulleted = "<li>"+String.Join((suffix??"")+"</li><li>",items.ToArray())+"</li>";
return bulleted;
}
}
leaving only:
private void LoadNavigation(Uri urlPrefix)
{
var links = _navigationLoader.LoadNavigationItems()
.Select(x => x.ToHtmlLink(urlPrefix))
.ToHtmlBullets("|");
navList.InnerHtml += links;
}
This method might now be more accurately named something like AddNavigationLinks. I'm also inclined to make this method side-effect free by passing navList into the method, I just don't happen to know what its type is.
<pre>
tag does not enable syntax highlighting (though<code>
does, but don't use that either) and more importantly: It does not escape HTML special characters. So your code did not display correctly using<pre>
tags. Thanks. \$\endgroup\$navList
? A class variable? \$\endgroup\$