Skip to content

HTML with CSS or JavaScript

axunonb edited this page Nov 22, 2024 · 7 revisions

What is the issue?

A frequent question being asked is: We get errors when using SmartFormat with a format string that contains HTML with CSS and/or JavaScript included.

While processing pure HTML works absolutely fine, the result becomes unpredictable with CSS and/or JavaScript.

The reason is obvious: SmartFormat uses braces to identify Placeholders, which are at the same time part of the CSS/JavaScript notation.

Important:

Whenever you are dealing with HTML, CSS, or JavaScript, it is highly recommended to sanitize the content and check for malicious code before processing it with SmartFormat, especially when the content is user input or third-party content.

Solutions

1. Modify SmartSettings

In v2, you could get the desired results, when setting Settings.ParseErrorAction = ErrorAction.MaintainTokens. This may still help with v3.

Recommended in v3:

We introduced bool ParserSettings.ParseInputAsHtml. The default is false.

If true, theParser will parse all content inside <script> and <style> tags as LiteralText. LiteralText does not parse Placeholders. All other places may still contain Placeholders. Note: the script and style tags must not contain whitespace. < script > or alike will not work.

This is because <script> and <style> tags may contain curly or square braces, that interfere with the SmartFormat {Placeholder} syntax.

Best results can only be expected with clean HTML: balanced opening and closing tags, single and double quotes. Also, do not use angle brackets, single and double quotes in script or style comments.

2. Pre-Process HTML with an HTML Parser

SmartFormat is not a fully-fledged HTML parser. If this is required, use AngleSharp or HtmlAgilityPack.

Therefore, it is strongly recommended to pre-process HTML with CSS/JavaScript using the AngleSharp library.

The following sample shows that only three extra lines of code will help.

Note: The example assumes, that CSS/JavaScript is located outside the <body>tag.

using AngleSharp;

Here is the HTML part:

var html = @"
<html>
    <head>
        <script>
            (function() {
                var ep;
                var loginState;
                try {
                    window.localStorage && (ep = JSON.parse(window.localStorage.getItem('dl_ep') || 'false'));
                window.localStorage && (loginState = JSON.parse(window.localStorage.getItem('dl_loginState')) || undefined);
            } catch(e) {
                console.error(e);
            }
        </script>
        <style type='text/css'>
            .site-sticky-top {
                position: -webkit-sticky;
                position: sticky;
                top: 0;
                z-index: 1020;
            }
        </style>
    </head>
    <body>
        <div class='main'>
            My name is {Name}. I'm living in {City}.
        </div>
    </body>
</html>
";

Here's the code for parsing HTML with AngleSharp and formatting with SmartFormat:

var variables = new { Name = "John Long", City = "New York" };

// Create a new parser front-end (can be re-used)
var parser = new AngleSharp.Html.Parser.HtmlParser();

// Get the DOM representation
AngleSharp.Html.Dom.IHtmlDocument htmlDocument = parser.ParseDocument(html);

// ##### Smart.Format the HTML body: #####
htmlDocument.Body.InnerHtml = Smart.Format(htmlDocument.Body.InnerHtml, variables);

// This gets the complete HTML as a string
var result = htmlDocument.ToHtml();
Clone this wiki locally