Beautiful Elixir DSL for building XML documents, backed by Saxy for escaping and encoding.

import XM

document do
  urlset xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9" do
    for page <- pages do
      url do
        loc site_url <> page.path
        lastmod page.date
      end
    end
  end
end

XM is intentionally tiny: local calls become XML elements, keyword arguments become attributes, and normal Elixir expressions still work.

Features

  • Nested XML elements with Elixir do/end syntax.
  • Attributes via keyword lists or maps.
  • Dynamic/namespaced tag names with tag/2.
  • for, if, unless, and case inside XML blocks.
  • Explicit text/1, comment/1, and cdata/1 nodes.
  • Binary rendering with render/2 and iodata rendering with render_iodata/2.
  • Saxy-backed escaping and XML encoding.

Installation

def deps do
  [
    {:xm, "~> 0.1.0"}
  ]
end

Examples

Sitemap

import XM

pages = [
  %{path: "/", date: ~D[2026-06-25]},
  %{path: "/about/", date: ~D[2026-06-25]}
]

xml =
  document do
    urlset xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9" do
      for page <- pages do
        url do
          loc "https://example.com" <> page.path
          lastmod page.date
        end
      end
    end
  end

Atom entry with CDATA

import XM

document do
  entry do
    title "Hello"

    content type: "html" do
      cdata "<p>Hello from XML</p>"
    end
  end
end

Namespaced or dynamic tags

import XM

tree do
  tag "media:thumbnail", url: "https://example.com/image.png"
end

License

MIT © 2026 Danila Poyarkov