with the help of the Stack overflow community I have been able to take some data from an XML document and add it to a list using the following code.
String URLString = "https://api3.libcal.com/api_hours_grid.php?iid=4246&format=xml&weeks=1&systemTime=0";
XDocument xdoc = new XDocument();
xdoc = XDocument.Load(URLString);
var location = (from p in xdoc.Descendants("location")
from s in p.Descendants("week").Elements()
select new
{
CampusName = (string)p.Element("name"),
WeekD = (string)s.Element("date"),
OpenHours = (string)s.Element("rendered"),
Day = s.Name.LocalName
}).ToList();
this works great, and I can output to an unordered list with the following
string currentLocation = "";
foreach (var item in location)
{
if (item.CampusName != currentLocation)
{
<h2>@item.CampusName</h2>
currentLocation = @item.CampusName;
}
<ul>
<li>@item.WeekD - @item.OpenHours</li>
</ul>
}
however, after reviewing my requirements I feel the data would be better displayed using a HTML Table. I have tried a few different ways using String builder to achieve this
string dayStop = "Sunday";
StringBuilder sb = new StringBuilder();
sb.Append("<TABLE>\n");
sb.Append("<TR>\n");
foreach (var item in location)
{
if (item.Day != dayStop)
{
sb.Append("<TH>\n");
sb.Append(@item.Day);
sb.Append("</TH>\n");
//dayStop = @item.Day;
}
}
sb.Append("</TR>\n");
sb.Append("<TR>\n");
sb.Append("<TD>\n");
sb.Append(@item.CampusName);
sb.Append("</TD>\n");
sb.Append("<TD>\n");
sb.Append(@item.OpenHours);
sb.Append("</TD>\n");
sb.Append("</TR>\n");
sb.Append("</TABLE > ");
}
Html.Raw(sb)
but its not working. I'd like the value of @item.Day to populate the value of TH, but as each item in my list contains value day value for each @item.CampusName I end up with a whole bunch of unnecessary @item.Day values and I feel like foreach is not the right answer here. What I'd like to end up with is something like the following snippet;
<table>
<tr>
<th>
Location
</th>
<th>
Sunday
</th>
<th>
Monday
</th>
<th>
Tueday
</th>
</tr>
<tr>
<td>
Campus 1
</td>
<td>
9 - 5
</td>
<td>
9 - 5
</td>
<td>
9 - 5
</td>
</tr>
<tr>
<td>
Campus 2
</td>
<td>
9 - 5
</td>
<td>
9 - 5
</td>
<td>
9 - 5
</td>
</tr>
</table>
In your xml you have multiple Days
so for th
you have to take distinct from those days and render
And for successive tr
you have to group each of your row by its CampusName
Try below code that will help you to gt your desired result.
The best practice is to write the below code in your action method and pass result to your razor view by using viewbag or viewmodel. Your posted code in question is in razor view so I implemented my code in razor also.
<div>
@{
String URLString = "https://api3.libcal.com/api_hours_grid.php?iid=4246&format=xml&weeks=1&systemTime=0";
XDocument xdoc = new XDocument();
xdoc = XDocument.Load(URLString);
var location = (from p in xdoc.Descendants("location")
from s in p.Descendants("week").Elements()
select new
{
CampusName = (string)p.Element("name"),
WeekD = (string)s.Element("date"),
OpenHours = (string)s.Element("rendered"),
Day = s.Name.LocalName
}).ToList();
string dayStop = "Sunday";
StringBuilder sb = new StringBuilder();
sb.Append("<table>\n");
sb.Append("<tr>\n");
string currentLocation = "";
foreach (var item in location.GroupBy(x => x.Day).Select(x => x.First()))
{
if (item.CampusName != currentLocation)
{
sb.Append("<th style='width:150px;'>\n");
sb.Append("Location");
sb.Append("</th>\n");
currentLocation = item.CampusName;
}
if (item.Day != dayStop)
{
sb.Append("<th style='width:150px;'>\n");
sb.Append(item.Day);
sb.Append("</th>\n");
}
}
sb.Append("</tr>\n");
currentLocation = "";
foreach (var item in location.GroupBy(x => x.CampusName))
{
sb.Append("<tr>\n");
foreach (var innerItem in item)
{
if (innerItem.CampusName != currentLocation)
{
sb.Append("<td>\n");
sb.Append(innerItem.CampusName);
sb.Append("</td>\n");
currentLocation = innerItem.CampusName;
}
if (innerItem.Day != dayStop)
{
sb.Append("<td>\n");
sb.Append(innerItem.OpenHours);
sb.Append("</td>\n");
}
}
sb.Append("</tr>\n");
}
@Html.Raw(sb.ToString());
}
</div>
OR You can also use html to razor view and in that you don't need to use StringBuilder
and this even more easy than above code.
@{
string currentLocation1 = "";
string currentLocation2 = "";
string dayStop1 = "Sunday";
}
<table>
<thead>
<tr>
@foreach (var item in location.GroupBy(x => x.Day).Select(x => x.First()))
{
if (item.CampusName != currentLocation1)
{
<th style='width:150px;'>Location</th>
currentLocation1 = item.CampusName;
}
if (item.Day != dayStop1)
{
<th style='width:150px;'>@item.Day</th>
}
}
</tr>
</thead>
<tbody>
@foreach (var item in location.GroupBy(x => x.CampusName))
{
<tr>
@foreach (var innerItem in item)
{
if (innerItem.CampusName != currentLocation2)
{
<td>@innerItem.CampusName</td>
currentLocation2 = innerItem.CampusName;
}
if (innerItem.Day != dayStop1)
{
<td>@innerItem.OpenHours</td>
}
}
</tr>
}
</tbody>
</table>
Output from both of above snippet: