elemi.generator

This module provides syntax for generating HTML and XML documents from inside of D. It supports embedded control flow (if, foreach, etc) and writing to output ranges.

See the examples to get started!

Note that the generator, at the moment, only supports HTML generation. While its output should be a valid XML document, it is unable to create tags other than HTML's own. The old XML API should still be suitable for use with XML.

Members

Aliases

mustuse
alias mustuse = AliasSeq!()
Undocumented in source.

Functions

buildHTML
HTML buildHTML(T range)

Write HTML elements to an output range.

buildHTML
TextHTML buildHTML()

Write HTML elements to a string or Element.

Structs

DocumentOutput
struct DocumentOutput

A wrapper over a function, with additional methods added to support XML/HTML generation.

HTML
struct HTML

A set of HTML tags to build documents with.

HTMLTag
struct HTMLTag(string name)

HTML tag builder.

Tag
struct Tag

Generic XML or HTML tag.

TextHTML
struct TextHTML

Supporting structure for buildHTML.

Examples

The buildHTML function is the entrypoint to generating HTML. Connect it to a HTML source: a function to fill the HTML document with content.

string output = buildHTML() ~ (html) {

};

Elements are created using a tilde, followed by curly braces. This syntax is called an element block.

string output = buildHTML() ~ (html) {
    html.div ~ {
        html.span ~ { };
    };
};
assert(output == "<div><span></span></div>");

Instead of a block, you can follow an element with a string to specify text content.

string output = buildHTML() ~ (html) {
    html.p ~ "Hello, World!";
};
assert(output == "<p>Hello, World!</p>");

You can add attributes to an element using the Tag.attr method.

string output = buildHTML() ~ (html) {
    html.a.attr("href", "https://example.com") ~ "Visit my website!";
};
assert(output == `<a href="https://example.com">Visit my website!</a>`);

Common HTML attributes are available through specialized methods.

string output = buildHTML() ~ (html) {
    html.div.id("my-div") ~ { };
    html.div.classes("one", "two", "three") ~ { };
    html.a.href("https://example.com") ~ { };
};
assert(output == `<div id="my-div"></div>`
    ~ `<div class="one two three"></div>`
    ~ `<a href="https://example.com"></a>`);

Use control flow statements like if and foreach to generate HTML with code.

string output = buildHTML() ~ (html) {
    html.ul ~ {
        foreach (item; ["1", "2", "3"]) {
            html.li ~ item;
        }
    };
};
assert(output == `<ul><li>1</li><li>2</li><li>3</li></ul>`);

Omit the tag name to append text directly.

string output = buildHTML() ~ (html) {
    html ~ "Hello, ";
    html.strong ~ "World!";
};
assert(output == "Hello, <strong>World!</strong>");

Keep your document safe from XSS injections: all HTML content is escaped automatically.

Warning: Elemi will not escape javascript links. If you let your users input URLs, make sure to block the javascript: schema.

string output = buildHTML() ~ (html) {
    html ~ "<script>alert('fool!')</script>";
    html.input.attr("value", "\" can't quit me") ~ { };
    html.div.classes("classes are <no exception>") ~ { };
};

assert(output == `&lt;script&gt;alert(&#39;fool!&#39;)&lt;/script&gt;`
    ~ `<input value="&quot; can&#39;t quit me"/>`
    ~ `<div class="classes are &lt;no exception&gt;"></div>`);

Interpolated expression strings, aka istrings, are supported.

string output = buildHTML() ~ (html) {
    const user = "<user>";
    html ~ i"Hello $(user)";
    html.div ~ i"Hello $(user)";
    html.div.attr("name", i"$(user)") ~ { };
    html.a.href(i"https://example.com/$(user)") ~ { };
    html.a
        .classes("button", "special")
        .href("https://example.com/") ~ { };
};
assert(output == `Hello &lt;user&gt;`
    ~ `<div>Hello &lt;user&gt;</div>`
    ~ `<div name="&lt;user&gt;"></div>`
    ~ `<a href="https://example.com/&lt;user&gt;"></a>`
    ~ `<a class="button special" href="https://example.com/"></a>`);

This syntax can be mixed with elements generated by the old syntax.

string output = buildHTML() ~ (html) {
    html ~ elem!"span"();
    html.div ~ elem!"span"();
    html ~ i"$(elem!"span"())";
};
assert(output == `<span></span>`
    ~ `<div><span></span></div>`
    ~ `<span></span>`);

Elemi works at compile time!

enum output = buildHTML ~ (html) {
    html.div ~ {
        html.p ~ "Hello, World!";
    };
};
assert(output == "<div><p>Hello, World!</p></div>");

Meta

History

  • Introduced in Elemi 1.4.0