I did this once before and it was very helpful for me. I am an amateur programmer and don't have more seasoned programmers around me to assist and help me grow. Any feedback on this critique is greatly appreciated!
What I've got is a C# class which takes some basic markup from a user (usually from a basic online textbox) and outputs a nicely formatted HTML table. I've included the markup, HTML output, and source code below. Again, all feedback\constructive criticism is greatly appreciated.
I am also curious how much time this would take a seasoned programmer? It took me about 6-6.5 hours.
The Markup
[grid]
border=0, align=center, width=95%
|(c=vdsa) VDS-A|(c=vdsb) VDS-B|(c=vdsc featured) VDS-C
RAM|1GB|2GB|(c=featured) 4GB
CPU|(c=nofeature)|(c=nofeature)
<a href="http://www.google.com">Google</a>|(c=yesfeature)|(c=nofeature)|(C=nofeature)
[/grid]
The Output HTML
<table align="center" border="0" width="95%">
<tr>
<th></th><th class="vdsa">VDS-A</th><th class="vdsb">VDS-B</th><th class="vdsc featured">VDS-C</th>
</tr><tr>
<td>RAM</td><td>1GB</td><td>2GB</td><td class="featured">4GB</td>
</tr><tr>
<td>CPU</td><td class="nofeature"></td><td class="nofeature" colspan="2"></td>
</tr><tr>
<td><a href="http://www.google.com">Google</a></td><td class="yesfeature"></td><td class="nofeature"></td><td class="nofeature"></td>
</tr>
</table>
The C# Class
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.UI;
namespace GridMarkup
{
public class GridProcessor
{
public string MarkupOpenTag { get; set; }
public string MarkupCloseTag { get; set; }
public string[] AllowedTableOptions { get; set; }
private string[] _rowSplitter = { "\r\n" };
private char _columnSplitter = '|';
private string _optionAssignmentOperator = "=";
private char[] _optionEndOperators = { ',', '\r', '\n', ' ' };
private int _columnsInGrid = -1;
private string _cssAssignmentOperator = "(c=";
private string _cssEndOperator = ")";
public GridProcessor() {
MarkupOpenTag = "[grid]";
MarkupCloseTag = "[/grid]";
AllowedTableOptions = new string[] { "align", "border", "cellpadding", "cellspacing", "width" };
}
public string Transform(string text)
{
if (string.IsNullOrEmpty(text)) return "";
string output = string.Empty;
int currentCurserLocation = 0;
while (currentCurserLocation < text.Length)
{
// try to find an opening grid tag.
int gridStart = text.ToLower().IndexOf(MarkupOpenTag.ToLower(), currentCurserLocation);
if (gridStart > -1)
{
// we have our opening tag, try to find an end tag.
int gridEnd = text.ToLower().IndexOf(MarkupCloseTag.ToLower(), currentCurserLocation);
if (gridEnd > -1)
{
// we have ourselves a grid! check for data between grids.
if (gridStart > currentCurserLocation)
{
output += text.Substring(currentCurserLocation, gridStart - currentCurserLocation);
}
// let's get the data out of the grid.
string gridText = text.Substring(gridStart + MarkupOpenTag.Length, gridEnd - gridStart - MarkupOpenTag.Length);
output += ProcessGrid(gridText);
// we are done with this grid, move the curser forward.
currentCurserLocation = gridEnd + MarkupCloseTag.Length;
}
else
{
output += text.Substring(currentCurserLocation, text.Length - currentCurserLocation);
currentCurserLocation = text.Length;
}
}
else
{
output += text.Substring(currentCurserLocation, text.Length - currentCurserLocation);
currentCurserLocation = text.Length;
}
}
return output;
}
private string ProcessGrid(string gridText)
{
StringBuilder sb = new StringBuilder();
string[] gridRows = gridText.Split(_rowSplitter, StringSplitOptions.RemoveEmptyEntries);
using (HtmlTextWriter writer = new HtmlTextWriter(new StringWriter(sb)))
{
//for the first line, check for table options
int startIndex = 0;
bool optionsFound = false;
foreach (string option in AllowedTableOptions)
{
int optionStart = gridRows[0].ToLower().IndexOf(option.ToLower() + _optionAssignmentOperator);
if (optionStart > -1)
{
int optionEnd = gridRows[0].ToLower().IndexOfAny(_optionEndOperators, optionStart);
if (optionEnd == -1)
optionEnd = gridRows[0].Length;
writer.AddAttribute(option, gridRows[0].Substring(optionStart + option.Length + 1, optionEnd - optionStart - option.Length - 1));
optionsFound = true;
}
}
if (optionsFound)
startIndex += 1;
writer.RenderBeginTag(HtmlTextWriterTag.Table);
for (int i = startIndex; i < gridRows.Count(); i++)
{
ProcessGridRow(gridRows[i], writer, (i == startIndex) ? HtmlTextWriterTag.Th : HtmlTextWriterTag.Td);
}
writer.RenderEndTag(); // end table
}
return sb.ToString();
}
private void ProcessGridRow(string rowText, HtmlTextWriter writer, HtmlTextWriterTag dataTag)
{
string[] rowColumns = rowText.Split(_columnSplitter);
int rowColumnsCount = rowColumns.Count();
int colSpan = 0;
// this is our header, so it defines the number of columns
if (dataTag == HtmlTextWriterTag.Th)
_columnsInGrid = rowColumnsCount;
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
for (int i = 0; i < rowColumnsCount; i++)
{
// if this is the last column, check to see if we need to set a colspan
if (i == rowColumnsCount - 1)
colSpan = _columnsInGrid - rowColumnsCount + 1;
ProcessGridColumn(rowColumns[i], writer, dataTag, colSpan);
}
writer.RenderEndTag(); // end tr
}
private void ProcessGridColumn(string columnText, HtmlTextWriter writer, HtmlTextWriterTag dataTag, int colSpan)
{
string innerColumnText = columnText;
// check to see if there are any css class assignments
int cssStart = columnText.ToLower().IndexOf(_cssAssignmentOperator.ToLower());
if (cssStart > -1)
{
// we found the start of a css assignment, lets see if we can find the end
int cssEnd = columnText.IndexOf(_cssEndOperator, cssStart + _cssAssignmentOperator.Length);
if (cssEnd > -1)
{
// we've got the end, now lets add the css attribute.
string cssClasses = columnText.Substring(cssStart + _cssAssignmentOperator.Length, cssEnd - cssStart - _cssAssignmentOperator.Length);
writer.AddAttribute(HtmlTextWriterAttribute.Class, cssClasses);
innerColumnText = columnText.Remove(cssStart, _cssAssignmentOperator.Length + _cssEndOperator.Length + cssClasses.Length).Trim();
}
}
if (colSpan > 1)
writer.AddAttribute(HtmlTextWriterAttribute.Colspan, colSpan.ToString());
writer.RenderBeginTag(dataTag);
writer.Write(innerColumnText);
writer.RenderEndTag();
}
}
}