Liking cljdoc? Tell your friends :D

hiccup-templating.core

EDN-driven Hiccup template engine. Templates are stored as EDN and filled at runtime with a Clojure data map, producing a Hiccup vector tree that can then be rendered to XHTML for downstream sinks (flying-saucer PDF pipeline, HTTP responses, email bodies, ...).

Tagged-literal grammar

Tag Meaning


:data/foo.bar Look up [:foo :bar] in data. Resolves to the value, or to the ::missing sentinel when absent / nil.

#data/foo.bar <form> Back-compat shorthand for #when :data/foo.bar <form> - used by the original template; kept so old templates still parse.

#when <test> <body> Splice <body> if <test> resolves; drop otherwise. <body> can be a single form or a vector of forms.

#when-not <test> <body> Inverse of #when.

#when-and [<tests>] <body> Splice <body> if EVERY test in the <tests> vector resolves. Cheap way to gate a row on multiple data paths.

#when-or [<tests>] <body> Splice <body> if AT LEAST ONE test in <tests> resolves.

#or [<expr> <fallback>] Evaluate <expr>; if it resolves to ::missing, evaluate <fallback>. Two special fallbacks are recognised: :remove/element drop the element that holds this #or. :remove/parent drop the parent of that element. Any other fallback is spliced as a plain value.

How element removal works

:remove/element and :remove/parent are not values - they are sentinels that propagate up the walk:

  • a vector / list whose child returned ::drop-element drops itself (returns ::missing so it disappears from its own parent);
  • a vector / list whose child returned ::drop-parent returns ::drop-element, so the level above drops itself instead.

That two-hop hand-off means :remove/parent deletes exactly the element one level above the #or form - typically a :tr row whose inner :td referenced a missing value.

Public API

Reading templates:

from-file Load an EDN template from disk. Optional :validatepath true rejects .. segments in the path or filename and refuses any file whose canonical path escapes the supplied base directory. Without the flag the caller is trusted with the file-system boundary. from-stream Read an EDN template from a PushbackReader (e.g. an uploaded stream). from-string Read an EDN template from a string (e.g. a slurped file).

Filling templates:

template-to-hiccup Walk a template + data map, returning a Hiccup vector tree with missing branches pruned. The template slot read is :template by default; override with :template-key.

Rendering to XHTML:

as-xhtml-string / as-xhtml-stream Render a Hiccup tree to XHTML (with <!DOCTYPE>). String values are emitted unescaped so pre-built HTML fragments (&nbsp;, <br/>, ...) survive - use these when the sink is the flying-saucer PDF pipeline and the data map is trusted. as-xhtml-string-escaped / as-xhtml-stream-escaped Same as above but HTML-escapes every string value in the tree. Use these when rendering to any HTML sink where the data map may contain user input.

EDN-driven Hiccup template engine.
Templates are stored as EDN and filled at runtime with a Clojure
data map, producing a Hiccup vector tree that can then be rendered
to XHTML for downstream sinks (flying-saucer PDF pipeline, HTTP
responses, email bodies, ...).

## Tagged-literal grammar
Tag                              Meaning
-------------------------------- ----------------------------------------
`:data/foo.bar`                  Look up `[:foo :bar]` in `data`.
                                 Resolves to the value, or to the
                                 `::missing` sentinel when absent / nil.

`#data/foo.bar <form>`           Back-compat shorthand for
                                 `#when :data/foo.bar <form>` - used by
                                 the original template; kept so old
                                 templates still parse.

`#when <test> <body>`            Splice `<body>` if `<test>` resolves;
                                 drop otherwise. `<body>` can be a
                                 single form or a vector of forms.

`#when-not <test> <body>`        Inverse of `#when`.

`#when-and [<tests>] <body>`     Splice `<body>` if EVERY test in the
                                 `<tests>` vector resolves. Cheap way
                                 to gate a row on multiple data
                                 paths.

`#when-or  [<tests>] <body>`     Splice `<body>` if AT LEAST ONE
                                 test in `<tests>` resolves.

`#or [<expr> <fallback>]`        Evaluate `<expr>`; if it resolves to
                                 `::missing`, evaluate `<fallback>`.
                                 Two special fallbacks are recognised:
                                   `:remove/element`  drop the element
                                                      that holds this
                                                      `#or`.
                                   `:remove/parent`   drop the parent
                                                      of that element.
                                 Any other fallback is spliced as a
                                 plain value.

## How element removal works

`:remove/element` and `:remove/parent` are not values - they are
sentinels that propagate up the walk:

  * a vector / list whose child returned `::drop-element` drops itself
    (returns `::missing` so it disappears from its own parent);
  * a vector / list whose child returned `::drop-parent` returns
    `::drop-element`, so the level above drops itself instead.

That two-hop hand-off means `:remove/parent` deletes exactly the
element one level above the `#or` form - typically a `:tr` row whose
inner `:td` referenced a missing value.

## Public API

Reading templates:

`from-file`    Load an EDN template from disk. Optional
               `:validatepath true` rejects `..` segments in the
               path or filename and refuses any file whose canonical
               path escapes the supplied base directory. Without
               the flag the caller is trusted with the file-system
               boundary.
`from-stream`  Read an EDN template from a `PushbackReader` (e.g.
               an uploaded stream).
`from-string`  Read an EDN template from a string (e.g. a slurped
               file).

Filling templates:

`template-to-hiccup`
               Walk a template + data map, returning a Hiccup vector
               tree with missing branches pruned. The template slot
               read is `:template` by default; override with
               `:template-key`.

Rendering to XHTML:

`as-xhtml-string` / `as-xhtml-stream`
               Render a Hiccup tree to XHTML (with `<!DOCTYPE>`).
               String values are emitted **unescaped** so pre-built
               HTML fragments (`&nbsp;`, `<br/>`, ...) survive - use
               these when the sink is the flying-saucer PDF pipeline
               and the data map is trusted.
`as-xhtml-string-escaped` / `as-xhtml-stream-escaped`
               Same as above but HTML-escapes every string value in
               the tree. Use these when rendering to any HTML sink
               where the data map may contain user input.
raw docstring

as-xhtml-streamclj

(as-xhtml-stream hiccup-ds)

Renders a Hiccup datastructure as XHTML 1.0 strict and returns it as a java.io.ByteArrayOutputStream. String values are emitted unescaped so pre-built HTML fragments survive - intended for the flying-saucer PDF pipeline with a trusted data map. Use as-xhtml-stream-escaped if the data map may contain user input.

Renders a Hiccup datastructure as XHTML 1.0 strict and returns
it as a `java.io.ByteArrayOutputStream`. String values are emitted
**unescaped** so pre-built HTML fragments survive - intended for the
flying-saucer PDF pipeline with a trusted data map. Use
`as-xhtml-stream-escaped` if the data map may contain user input.
sourceraw docstring

as-xhtml-stream-escapedclj

(as-xhtml-stream-escaped hiccup-ds)

Renders a Hiccup datastructure as XHTML 1.0 strict and returns it as a java.io.ByteArrayOutputStream. Every string value in the tree is HTML-escaped, making this the safe choice when rendering to any HTML sink with a data map that may contain user input.

Renders a Hiccup datastructure as XHTML 1.0 strict and returns
it as a `java.io.ByteArrayOutputStream`. Every string value in the
tree is HTML-escaped, making this the safe choice when rendering to
any HTML sink with a data map that may contain user input.
sourceraw docstring

as-xhtml-stringclj

(as-xhtml-string hiccup-ds)

Renders a Hiccup datastructure as XHTML 1.0 strict and returns it as a string. String values are emitted unescaped so pre-built HTML fragments survive - intended for the flying-saucer PDF pipeline with a trusted data map. Use as-xhtml-string-escaped if the data map may contain user input.

Renders a Hiccup datastructure as XHTML 1.0 strict and returns
it as a string. String values are emitted **unescaped** so pre-built
HTML fragments survive - intended for the flying-saucer PDF pipeline
with a trusted data map. Use `as-xhtml-string-escaped` if the data
map may contain user input.
sourceraw docstring

as-xhtml-string-escapedclj

(as-xhtml-string-escaped hiccup-ds)

Renders a Hiccup datastructure as XHTML 1.0 strict and returns it as a string. Every string value in the tree is HTML-escaped, making this the safe choice when rendering to any HTML sink with a data map that may contain user input.

Renders a Hiccup datastructure as XHTML 1.0 strict and returns
it as a string. Every string value in the tree is HTML-escaped,
making this the safe choice when rendering to any HTML sink with a
data map that may contain user input.
sourceraw docstring

from-fileclj

(from-file path filename & {:keys [validatepath max-bytes max-depth]})

Reads an EDN template file at <path>/<filename>. Trailing slashes on path are tolerated; filename must end in .edn.

Options (all opt-in): :validatepath true - reject .. segments in path or filename and refuse any file whose canonical path escapes the canonicalised path. :max-bytes n - refuse to read the file if its size exceeds n bytes, and abort mid-read once more than n characters have streamed. :max-depth n - throw ex-info if the template's nesting depth exceeds n during the reader postwalk.

Throws ex-info when the extension check fails, when the file does not exist, when :validatepath true catches an escape attempt, or when a size / depth limit is exceeded.

Reads an EDN template file at `<path>/<filename>`. Trailing
slashes on `path` are tolerated; `filename` must end in `.edn`.

Options (all opt-in):
  `:validatepath true` - reject `..` segments in `path` or `filename`
                         and refuse any file whose canonical path
                         escapes the canonicalised `path`.
  `:max-bytes n`       - refuse to read the file if its size exceeds
                         `n` bytes, and abort mid-read once more
                         than `n` characters have streamed.
  `:max-depth n`       - throw `ex-info` if the template's nesting
                         depth exceeds `n` during the reader
                         postwalk.

Throws `ex-info` when the extension check fails, when the file does
not exist, when `:validatepath true` catches an escape attempt, or
when a size / depth limit is exceeded.
sourceraw docstring

from-streamclj

(from-stream ednstream & {:keys [max-bytes max-depth]})

Reads an EDN template from a java.io.PushbackReader (e.g. an uploaded stream). Unknown tagged literals are preserved as tagged-literal values so the walker can interpret them later.

Options (all opt-in): :max-bytes n - abort mid-read once more than n characters have streamed through the reader. :max-depth n - throw ex-info if the template's nesting depth exceeds n during the reader postwalk.

Reads an EDN template from a `java.io.PushbackReader` (e.g. an
uploaded stream). Unknown tagged literals are preserved as
`tagged-literal` values so the walker can interpret them later.

Options (all opt-in):
  `:max-bytes n` - abort mid-read once more than `n` characters have
                   streamed through the reader.
  `:max-depth n` - throw `ex-info` if the template's nesting depth
                   exceeds `n` during the reader postwalk.
sourceraw docstring

from-stringclj

(from-string ednstring & {:keys [max-bytes max-depth]})

Reads an EDN template from a string (e.g. a slurped file). Unknown tagged literals are preserved as tagged-literal values so the walker can interpret them later.

Options (all opt-in): :max-bytes n - throw before parsing when the UTF-8 byte length of ednstring exceeds n. :max-depth n - throw ex-info if the template's nesting depth exceeds n during the reader postwalk.

Reads an EDN template from a string (e.g. a slurped file).
Unknown tagged literals are preserved as `tagged-literal` values so
the walker can interpret them later.

Options (all opt-in):
  `:max-bytes n` - throw before parsing when the UTF-8 byte length
                   of `ednstring` exceeds `n`.
  `:max-depth n` - throw `ex-info` if the template's nesting depth
                   exceeds `n` during the reader postwalk.
sourceraw docstring

template-to-hiccupclj

(template-to-hiccup template
                    data
                    &
                    {:keys [template-key max-depth]
                     :or {template-key :template}})

Walks the template slot under :template-key (default :template) of template, resolving :data/... lookups and tagged-literal directives against data. Returns the expanded Hiccup vector tree with missing branches pruned, or nil when the entire template resolves away.

Options: :template-key k - override which template slot to expand. Defaults to :template. :max-depth n - throw ex-info when the walker recurses more than n levels deep. Opt-in - nil (default) means no limit.

Walks the template slot under `:template-key` (default
`:template`) of `template`, resolving `:data/...` lookups and
tagged-literal directives against `data`. Returns the expanded
Hiccup vector tree with missing branches pruned, or `nil` when the
entire template resolves away.

Options:
  `:template-key k` - override which template slot to expand.
                       Defaults to `:template`.
  `:max-depth n`    - throw `ex-info` when the walker recurses more
                       than `n` levels deep. Opt-in - `nil`
                       (default) means no limit.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close