Library to easily generate XML with a clean Lua DSL.
luarocks install luaxmlgeneratorlocal xml_gen = require("xml-generator")
local xml = xml_gen.xml
local doc = xml.html {charset="utf-8", lang="en"} {
    xml.head {
        xml.title "Hello World"
    },
    xml.body {
        xml.h1 "Hello World",
        xml.div {id="numbers"} {
            function() --run as a coroutine
                for i = 1, 10 do
                    coroutine.yield(xml.p(i))
                end
            end
        }
    }
}
print(doc)Table of tags that should not be sanitized. By default, it contains script and style.
local xml_gen = require("xml-generator")
xml_gen.no_sanitize["mytag"] = true
local doc = xml_gen.xml.mytag [[
        Thsi will not be sanitized! <><><><><><%%%<>%<>%<>% you can use all of this!
]]
By default, within xml_gen.xml there is a special key called lua which just allows for _G to be accessed. This is useful if you use xml_gen.declare_generator, which overloads the _ENV (setfenv on 5.1), where the _G would not be ordinarily accessible.
local xml_gen = require("xml-generator")
local gen = xml_gen.declare_generator(function()
    return html {
        head {
            title "Hello World";
        };
        body {
            p { "The time of generation is ", lua.os.date() }
        };
    }
end)
print(gen())Using xml_gen.component you can create your own components. Here is an example of a random_number component
---@param context fun(args: { [string] : any }, children: XML.Children): XML.Node?
---@return XML.Component
function export.component(context)local xml_gen = require("xml-generator")
local xml = xml_gen.xml
math.randomseed(os.time())
local random_number = xml_gen.component(function(args, children)
    local min = args.min or 0
    --remove these from the args so they dont show up in our HTML attributes later
    args.min = nil
    local max = args.max or 100
    args.max = nil
    coroutine.yield(xml.p "This is a valid coroutine too!")
    return xml.span(args) {
        math.random(min, max),
        children --children is a table of all the children passed to the component, this may be empty
    }
end)
local doc = xml.html {
    xml.body {
        random_number {min = 0, max = 100};
        random_number {max=10} {
            xml.p "This is inside the span!"
        };
        random_number;
    }
}
print(doc)---@generic T
---@param func fun(...: T): XML.Node
---@return fun(...: T): XML.Node
function export.declare_generator(func)Allows you to create a function in which the _ENV is overloaded with the xml table. This allows you to write XML more concisely (see example above).
---@param css { [string | string[]] : { [string | string[]] : (number | string | string[]) } }
---@return XML.Node
function export.style(css)Creates an HTML style tag with the given table
local xml_gen = require("xml-generator")
local style = xml_gen.style {
    [{ "body", "html" }] = {
        margin = 0,
        padding = 0,
    },
    body = {
        background = "#000",
        color = "#fff",
    }
    --etc
}
print(style)---WILL NOT BE SANITIZED
---@param ... string
---@return string[]
function export.raw(...) endInserts raw (NOT SANITIZED) strings into the document.
## API
You do not need to generate XML with this library, instead, you can use an `XML.Node` as its own object.
```lua
---@class XML.Children
---@field [integer] XML.Node | string | fun(): XML.Node
---@class XML.AttributeTable : XML.Children
---@field [string] string | boolean | number
---@class XML.Node
---@operator call(XML.AttributeTable): XML.Node
---@field tag string
---@field children XML.Children
---@field attributes XML.AttributeTable
---@class XML.Component : XML.Node
---@field attributes { [string] : any } The attributes can be any type for `component`s, but not for `node`s
---@field context fun(args: { [string] : any }, children: XML.Children): XML.Node?
local xml_gen = require("xml-generator")
local xml = xml_gen.xml
local my_node = xml.div {id="my-div"} {
    xml.p {id="p-1"} "Hello World";
    xml.p {id="p-2"} "Hello World";
    xml.p {id="p-3"} "Hello World";
}
print(my_node.tag) --div
print(my_node.attributes.id) --my-div
for i, child in ipairs(my_node.children) do
    print(i, child.tag, child.attributes.id)
end
print(my_node)attributes and children can be empty, but will never be nil.
tag will be nil if the node is a component.