Write HTML to string

C#Html

C# Problem Overview


I have code like this. Is there a way to make it easier to write and maintain? Using C# .NET 3.5.

string header(string title)
{
    StringWriter s = new StringWriter();
    s.WriteLine("{0}","<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">");
    s.WriteLine("{0}", "<html>");
    s.WriteLine("<title>{0}</title>", title);
    s.WriteLine("{0}","<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">");
    s.WriteLine("{0}", "</head>");
    s.WriteLine("{0}", "<body>");
    s.WriteLine("{0}", "");
}

I could also just write:

s.WriteLine("{0}", @"blah blah

many
new
lines
blah UHY#$&_#$_*@Y KSDSD<>\t\t\t\t\t\tt\t\t\\\t\t\t\t\\\h\th'\h't\th
hi
done"); 

It will work, but I need to replace all " with "".

C# Solutions


Solution 1 - C#

You're probably better off using an http://msdn.microsoft.com/en-us/library/system.web.ui.htmltextwriter.aspx">`HtmlTextWriter`</a> or an https://msdn.microsoft.com/en-us/library/System.Xml.XmlWriter%28v=vs.110%29.aspx">`XMLWriter`</a> than a plain StringWriter. They will take care of escaping for you, as well as making sure the document is well-formed.

http://dotnetperls.com/htmltextwriter">This page shows the basics of using the HtmlTextWriter class, the gist of which being:

StringWriter stringWriter = new StringWriter();

using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter))
{
    writer.AddAttribute(HtmlTextWriterAttribute.Class, classValue);
    writer.RenderBeginTag(HtmlTextWriterTag.Div); // Begin #1

    writer.AddAttribute(HtmlTextWriterAttribute.Href, urlValue);
    writer.RenderBeginTag(HtmlTextWriterTag.A); // Begin #2

    writer.AddAttribute(HtmlTextWriterAttribute.Src, imageValue);
    writer.AddAttribute(HtmlTextWriterAttribute.Width, "60");
    writer.AddAttribute(HtmlTextWriterAttribute.Height, "60");
    writer.AddAttribute(HtmlTextWriterAttribute.Alt, "");

    writer.RenderBeginTag(HtmlTextWriterTag.Img); // Begin #3
    writer.RenderEndTag(); // End #3

    writer.Write(word);

    writer.RenderEndTag(); // End #2
    writer.RenderEndTag(); // End #1
}
// Return the result.
return stringWriter.ToString();

Solution 2 - C#

When I deal with this problem in other languages I go for a separation of code and HTML. Something like:

1.) Create a HTML template. use [varname] placeholders to mark replaced/inserted content.
2.) Fill your template variables from an array or structure/mapping/dictionary

Write( FillTemplate(myHTMLTemplate, myVariables) ) # pseudo-code

Solution 3 - C#

Use an XDocument to create the DOM, then write it out using an XmlWriter. This will give you a wonderfully concise and readable notation as well as nicely formatted output.

Take this sample program:

using System.Xml;
using System.Xml.Linq;

class Program {
    static void Main() {
        var xDocument = new XDocument(
            new XDocumentType("html", null, null, null),
            new XElement("html",
                new XElement("head"),
                new XElement("body",
                    new XElement("p",
                        "This paragraph contains ", new XElement("b", "bold"), " text."
                    ),
                    new XElement("p",
                        "This paragraph has just plain text."
                    )
                )
            )
        );

        var settings = new XmlWriterSettings {
            OmitXmlDeclaration = true, Indent = true, IndentChars = "\t"
        };
        using (var writer = XmlWriter.Create(@"C:\Users\wolf\Desktop\test.html", settings)) {
            xDocument.WriteTo(writer);
        }
    }
}

This generates the following output:

<!DOCTYPE html >
<html>
	<head />
	<body>
		<p>This paragraph contains <b>bold</b> text.</p>
		<p>This paragraph has just plain text.</p>
	</body>
</html>

Solution 4 - C#

I know you asked about C#, but if you're willing to use any .Net language then I highly recommend Visual Basic for this exact problem. Visual Basic has a feature called XML Literals that will allow you to write code like this.

Module Module1

    Sub Main()

        Dim myTitle = "Hello HTML"
        Dim myHTML = <html>
                         <head>
                             <title><%= myTitle %></title>
                         </head>
                         <body>
                             <h1>Welcome</h1>
                             <table>
                                 <tr><th>ID</th><th>Name</th></tr>
                                 <tr><td>1</td><td>CouldBeAVariable</td></tr>
                             </table>
                         </body>
                     </html>

        Console.WriteLine(myHTML)
    End Sub

End Module

This allows you to write straight HTML with expression holes in the old ASP style and makes your code super readable. Unfortunately this feature is not in C#, but you could write a single module in VB and add it as a reference to your C# project.

Writing in Visual Studio also allows proper indentation for most XML Literals and expression wholes. Indentation for the expression holes is better in VS2010.

Solution 5 - C#

return string.Format(@"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01//EN""      ""http://www.w3.org/TR/html4/strict.dtd"">
<html>
<title>{0}</title>
<link rel=""stylesheet"" type=""text/css"" href=""style.css"">
</head>
<body>
", title);

Solution 6 - C#

You could use System.Xml.Linq objects. They were totally redesigned from the old System.Xml days which made constructing XML from scratch really annoying.

Other than the doctype I guess, you could easily do something like:

var html = new XElement("html",
    new XElement("head",
        new XElement("title", "My Page")
    ),
    new XElement("body",
        "this is some text"
    )
);

Solution 7 - C#

The most straight forward way is to use an XmlWriter object. This can be used to produce valid HTML and will take care of all of the nasty escape sequences for you.

Solution 8 - C#

You can use T4 Templates for generating Html (or any) from your code. see this: http://msdn.microsoft.com/en-us/library/ee844259.aspx

Solution 9 - C#

You can use ASP.NET to generate your HTML outside the context of web pages. Here's an article that shows how it can be done.

Solution 10 - C#

If you're looking to create an HTML document similar to how you would create an XML document in C#, you could try Microsoft's open source library, the Html Agility Pack.

It provides an HtmlDocument object that has a very similar API to the System.Xml.XmlDocument class.

Solution 11 - C#

With the introduction of Razor in ASP.net MVC, the best way to write HTML in C# is with the Razor Engine.

string templatePath = $@"{Directory.GetCurrentDirectory()}\EmailTemplates"; 

IRazorLightEngine engine = EngineFactory.CreatePhysical(templatePath); 

var model = new Notification 
{ 
       Name = "Jone", 
       Title = "Test Email", 
       Content = "This is a test" 
}; 

string result = engine.Parse("template.cshtml", model); 

Template:

<h2>Dear @Model.Name, you have a notification.</h2> 
 
<h1>@Model.Title</h1> 
<p>@Model.Content</p> 
 
<p>Date:@DateTime.Now</p> 

For a complete sample, see here

Solution 12 - C#

You could use some third party open-source libraries to generated strong typed verified (X)HTML, such as [CityLizard Framework][1] or Sharp DOM.

Update For example

html
    [head
        [title["Title of the page"]]
        [meta_(
            content: "text/html;charset=UTF-8",
            http_equiv: "Content-Type")
        ]
        [link_(href: "css/style.css", rel: "stylesheet", type: "text/css")]
        [script_(type: "text/javascript", src: "/JavaScript/jquery-1.4.2.min.js")]
    ]
    [body
        [div
            [h1["Test Form to Test"]]
            [form_(action: "post", id: "Form1")
                [div
                    [label["Parameter"]]
                    [input_(type: "text", value: "Enter value")]
                    [input_(type: "submit", value: "Submit!")]
                ]
            ]
            [div
                [p["Textual description of the footer"]]
                [a_(href: "http://google.com/")
                    [span["You can find us here"]]
                ]
                [div["Another nested container"]]
            ]
        ]
    ];

[1]: http://citylizard.codeplex.com/ "CityLizard Framework"

Solution 13 - C#

This is not a generic solution, however, if your pupose is to have or maintain email templates then System.Web has a built-in class called MailDefinition. This class is used by the ASP.NET membership controls to create HTML emails.

Does the same kind of 'string replace' things as mentioned above, but packs it all into a MailMessage for you.

Here is an example from MSDN:

ListDictionary replacements = new ListDictionary();
replacements.Add("<%To%>",sourceTo.Text);
replacements.Add("<%From%>", md.From);
System.Net.Mail.MailMessage fileMsg;
fileMsg = md.CreateMailMessage(toAddresses, replacements, emailTemplate, this); 
return fileMsg;

Solution 14 - C#

You could write your own classes with its Render method, and another attributes, to avoid a great mess if you use it a lot, and then use the HTMLWriter or the xmlwriter as well. This logic is used in the asp.net pages, you can inherit from webControl and override the render method, wich is great if you are developing server-side controls.
This could be a good example.

Regards

Solution 15 - C#

It really depends what you are going for, and specifically, what kind of performance you really need to offer.

I've seen admirable solutions for strongly-typed HTML development (complete control models, be it ASP.NET Web Controls, or similar to it) that just add amazing complexity to a project. In other situations, it is perfect.

In order of preference in the C# world,

  • ASP.NET Web Controls
  • ASP.NET primitives and HTML controls
  • XmlWriter and/or HtmlWriter
  • If doing Silverlight development with HTML interoperability, consider something strongly typed like link text
  • StringBuilder and other super primitives

Solution 16 - C#

I wrote these classes which served me well. It's simple yet pragmatic.

public class HtmlAttribute
{
    public string Name { get; set; }
    public string Value { get; set; }

    public HtmlAttribute(string name) : this(name, null) { }

    public HtmlAttribute(
        string name,
        string @value)
    {
        this.Name = name;
        this.Value = @value;
    }

    public override string ToString()
    {
        if (string.IsNullOrEmpty(this.Value))
            return this.Name;

        if (this.Value.Contains('"'))
            return string.Format("{0}='{1}'", this.Name, this.Value);

        return string.Format("{0}=\"{1}\"", this.Name, this.Value);
    }
}

public class HtmlElement
{
    protected List<HtmlAttribute> Attributes { get; set; }
    protected List<object> Childs { get; set; }
    public string Name { get; set; }
    protected HtmlElement Parent { get; set; }

    public HtmlElement() : this(null) { }

    public HtmlElement(string name, params object[] childs)
    {
        this.Name = name;
        this.Attributes = new List<HtmlAttribute>();
        this.Childs = new List<object>();

        if (childs != null && childs.Length > 0)
        {
            foreach (var c in childs)
            {
                Add(c);
            }
        }
    }

    public void Add(object o)
    {
        var a = o as HtmlAttribute;
        if (a != null)
            this.Attributes.Add(a);
        else
        {
            var h = o as HtmlElement;
            if (h != null && !string.IsNullOrEmpty(this.Name))
            {
                h.Parent = this;
                this.Childs.Add(h);
            }
            else
                this.Childs.Add(o);
        }
    }

    public override string ToString()
    {
        var result = new StringBuilder();

        if (!string.IsNullOrEmpty(this.Name))
        {
            result.Append(string.Format("<{0}", this.Name));
            if (this.Attributes.Count > 0)
            {
                result.Append(" ");
                foreach (var attr in this.Attributes)
                {
                    result.Append(attr.ToString());
                    result.Append(" ");
                }

                result = new StringBuilder(result.ToString().TrimEnd(' '));
            }

            if (this.Childs.Count == 0)
            {
                result.Append(" />");
            }
            else
            {
                result.AppendLine(">");

                foreach (var c in this.Childs)
                {
                    var cParts = c.ToString().Split('\n');

                    foreach (var p in cParts)
                    {
                        result.AppendLine(string.Format("{0}", p));
                    }
                }

                result.Append(string.Format("</{0}>", this.Name));
            }
        }
        else
        {
            foreach (var c in this.Childs)
            {
                var cParts = c.ToString().Split('\n');

                foreach (var p in cParts)
                {
                    result.AppendLine(string.Format("{0}", p));
                }
            }
        }

        var head = GetHeading(this);

        var ps = result.ToString().Split('\n');
        return string.Join("\r\n", (from p in ps select head + p.TrimEnd('\r')).ToArray());
    }

    string GetHeading(HtmlElement h)
    {
        if (h.Parent != null)
            return "    ";
        else
            return string.Empty;
    }
}

Solution 17 - C#

HSharp is a library used to analyse markup language like HTML easily and fastly. Install: PM> Install-Package Obisoft.HSharp

        var Document = new HDoc(DocumentOptions.BasicHTML);
        Document["html"]["body"].AddChild("div");
        Document["html"]["body"]["div"].AddChild("a", new HProp("href", "/#"));
        Document["html"]["body"]["div"].AddChild("table");
        Document["html"]["body"]["div"]["table"].AddChildren(
         new HTag("tr"),
         new HTag("tr", "SomeText"),
         new HTag("tr", new HTag("td")));
        var Result = Document.GenerateHTML();
        Console.WriteLine(Result);

and output:

<html>
<head>
<meta charset="utf-8"></meta><title>
Example </title>
</head>
<body>
<div>
<a href="/#"></a><table>
<tr></tr><tr>
SomeText </tr>
<tr>
<td></td></tr>
</table>
</div>
</body>
</html>

Solution 18 - C#

I was looking for something that looked like jquery for generating dom in C# (I don't need to parse). Unfortunately no luck in finding a lightweight solution so I created this simple class that is inherited from System.Xml.Linq.XElement. The key feature is that you can chain the operator like when using jquery in javascript so it's more fluent. It's not fully featured but it does what I need and if there is interest I can start a git.

public class DomElement : XElement
{
	public DomElement(string name) : base(name)
	{
	}

	public DomElement(string name, string value) : base(name, value)
	{
	}

	public DomElement Css(string style, string value)
	{
		style = style.Trim();
		value = value.Trim();
		var existingStyles = new Dictionary<string, string>();
		var xstyle = this.Attribute("style");
		if (xstyle != null)
		{
			foreach (var s in xstyle.Value.Split(';'))
			{
				var keyValue = s.Split(':');
				existingStyles.Add(keyValue[0], keyValue.Length < 2 ? null : keyValue[1]);
			}
		}

		if (existingStyles.ContainsKey(style))
		{
			existingStyles[style] = value;
		}
		else
		{
			existingStyles.Add(style, value);
		}

		var styleString = string.Join(";", existingStyles.Select(s => $"{s.Key}:{s.Value}"));
		this.SetAttributeValue("style", styleString);

		return this;
	}

	public DomElement AddClass(string cssClass)
	{
		var existingClasses = new List<string>();
		var xclass = this.Attribute("class");
		if (xclass != null)
		{
			existingClasses.AddRange(xclass.Value.Split());
		}

		var addNewClasses = cssClass.Split().Where(e => !existingClasses.Contains(e));
		existingClasses.AddRange(addNewClasses);

		this.SetAttributeValue("class", string.Join(" ", existingClasses));
		return this;
	}

	public DomElement Text(string text)
	{
		this.Value = text;
		return this;
	}

	public DomElement Append(string text)
	{
		this.Add(text);
		return this;
	}
	
	public DomElement Append(DomElement child)
	{
		this.Add(child);
		return this;
	}
}

Sample:

void Main()
{
	var html = new DomElement("html")
		.Append(new DomElement("head"))
		.Append(new DomElement("body")
			.Append(new DomElement("p")
				.Append("This paragraph contains")
				.Append(new DomElement("b", "bold"))
				.Append(" text.")
				)
			.Append(new DomElement("p").Text("This paragraph has just plain text"))
			)
		;

	html.ToString().Dump();

	var table = new DomElement("table").AddClass("table table-sm").AddClass("table-striped")
			.Append(new DomElement("thead")
				.Append(new DomElement("tr")
					.Append(new DomElement("td").Css("padding-left", "15px").Css("color", "red").Css("color", "blue")
						.AddClass("from-now")
						.Append(new DomElement("div").Text("Hi there"))
						.Append(new DomElement("div").Text("Hey there"))
						.Append(new DomElement("div", "Yo there"))
						)
				)
			)
		;
	table.ToString().Dump();
}

output from above code:

<html>
  <head />
  <body>
    <p>This paragraph contains<b>bold</b> text.</p>
    <p>This paragraph has just plain text</p>
  </body>
</html>
<table class="table table-sm table-striped">
  <thead>
    <tr>
      <td style="padding-left:15px;color:blue" class="from-now">
        <div>Hi there</div>
        <div>Hey there</div>
        <div>Yo there</div>
      </td>
    </tr>
  </thead>
</table>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser34537View Question on Stackoverflow
Solution 1 - C#lc.View Answer on Stackoverflow
Solution 2 - C#SpliFFView Answer on Stackoverflow
Solution 3 - C#Daniel WolfView Answer on Stackoverflow
Solution 4 - C#Jim WallaceView Answer on Stackoverflow
Solution 5 - C#JimmyView Answer on Stackoverflow
Solution 6 - C#JoshView Answer on Stackoverflow
Solution 7 - C#JaredParView Answer on Stackoverflow
Solution 8 - C#oleg wxView Answer on Stackoverflow
Solution 9 - C#JacobView Answer on Stackoverflow
Solution 10 - C#Dan HerbertView Answer on Stackoverflow
Solution 11 - C#Greg GumView Answer on Stackoverflow
Solution 12 - C#Sergey ShandarView Answer on Stackoverflow
Solution 13 - C#Brendan KowitzView Answer on Stackoverflow
Solution 14 - C#matiView Answer on Stackoverflow
Solution 15 - C#Jeff WilcoxView Answer on Stackoverflow
Solution 16 - C#Kaveh ShahbazianView Answer on Stackoverflow
Solution 17 - C#MMAView Answer on Stackoverflow
Solution 18 - C#howardloView Answer on Stackoverflow