> For the complete documentation index, see [llms.txt](https://www.lisppad.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.lisppad.app/libraries/lispkit/lispkit-sxml.md).

# (lispkit sxml)

Library `(lispkit sxml)` provides utility procedures for rendering *SXML* as XML, HTML, or plain text. SXML is a representation of XML/HTML documents (and, more generally, of markup-oriented tree structures) as plain S-expressions. Libraries `(lispkit sxml xml)` and `(lispkit sxml html)` provide parsers that turn XML respectively HTML source text into SXML; this library provides the inverse direction as well as a few text-rendering and escaping utilities that are shared between the two parser libraries.

### SXML representation

An SXML node is one of the following:

* An *element*: a list whose first element (the *head*) is a symbol denoting the tag name, optionally followed by an *attribute list* as the first child, followed by zero or more child nodes. An attribute list is a list headed by the symbol `@`, containing `(name value)` (or, more generally, `(name . value)`) pairs, e.g. `(a (@ (href "https://example.org")) "Example")` represents `<a href="https://example.org">Example</a>`.
* An element without an attribute list and without children, e.g. `(br)`, is rendered as a self-closing tag, e.g. `<br/>`. An element with an attribute list but no further children, e.g. `(img (@ (src "logo.png")))`, is rendered with a separate closing tag, e.g. `<img src="logo.png"></img>`.
* A *text node*: typically a string, but any LispKit object for which a textual representation exists can be used as a leaf of an SXML tree (see below).
* A `@raw` node, e.g. `(@raw "<b>already escaped</b>")`, whose single string child is inserted verbatim into the output without any escaping. This is useful for embedding pre-rendered or externally sanitized markup.
* A *sequence* of SXML nodes represented as a list not starting with a symbol; the elements of the list are processed in order as if they were siblings.

Besides strings, the following LispKit objects can be used as SXML text nodes and are converted into their textual representation automatically: `#f` (rendered as the empty string), characters, symbols, numbers, styled text objects (see `(lispkit styled-text)`), date/time objects (see `(lispkit date-time)`), vectors, as well as Markdown blocks, block sequences and inline text objects (see `(lispkit markdown)`), which get rendered via the corresponding Markdown-to-HTML conversion. A full `markdown` document object embedded into an SXML tree is likewise converted to HTML.

Parsers such as `xml->sxml` (from `(lispkit sxml xml)`) and `html->sxml` (from `(lispkit sxml html)`) wrap the parsed document in a top-level `*TOP*` element, i.e. `(*TOP* node ...)`.

### Rendering SXML

**(display-sxml&#x20;*****sxml*****)** \[procedure]\
**(display-sxml&#x20;*****sxml port*****)**

Renders the (valid, expanded) SXML tree *sxml* as XML/HTML markup to output port *port*. If *port* is not provided, `display-sxml` writes to the current output port (as defined by `current-output-port` of library `(lispkit port)`). An element without an attribute list and without children is rendered as a self-closing tag; an element with an attribute list but no further children is rendered with a separate closing tag. A `@raw` node is considered to already be safe markup; its content is written to *port* without any escaping. All other text is HTML-escaped before it is written to *port*.

**(display-sxml-text&#x20;*****sxml*****)** \[procedure]\
**(display-sxml-text&#x20;*****sxml port*****)**

Renders the SXML tree *sxml* as plain text suitable for display in a terminal, writing the result to output port *port* (or to the current output port if *port* is not provided). All markup is stripped. `head`, `style`, and `script` elements are skipped entirely (together with their content). A newline is inserted after `p`, `li`, `br`, and `h1` to `h6` elements to preserve some of the visual structure of the original document.

**(sxml->xml&#x20;*****sxml*****)** \[procedure]

Returns a string containing the XML markup for the SXML tree *sxml*, as generated by `display-sxml`.

```scheme
(sxml->xml '(book (@ (id "1")) (title "SXML in a Nutshell")))
⇒ "<book id=\"1\"><title>SXML in a Nutshell</title></book>"
```

**(sxml->html&#x20;*****sxml*****)** \[procedure]

Returns a string containing the HTML markup for the SXML tree *sxml*, as generated by `display-sxml`.

```scheme
(sxml->html '(p "Hello, " (b "World") "!"))
⇒ "<p>Hello, <b>World</b>!</p>"
```

**(sxml->text&#x20;*****sxml*****)** \[procedure]

Returns a string containing a plain-text rendering of the SXML tree *sxml*, as generated by `display-sxml-text`.

**(sxml-strip&#x20;*****sxml*****)** \[procedure]

Returns a string consisting of the concatenation of all string-valued leaves contained in the SXML tree *sxml*, with all tags and non-string leaves (such as numbers or symbols) removed. Unlike `sxml->text`, `sxml-strip` performs no formatting; it simply concatenates the string content of the tree in document order. Note that `sxml-strip` does not special-case `@` attribute lists, so string-valued attribute values contribute to the result as well.

```scheme
(sxml-strip '(p "Hello, " (b "World") "!"))
⇒ "Hello, World!"
```

### Escaping utilities

**(html-escape&#x20;*****obj*****)** \[procedure]

Returns a string containing the HTML-escaped textual representation of *obj*. *obj* can be a string or any other object that can be used as an SXML text node (see above). All characters requiring an HTML entity encoding (such as `<`, `>`, `&`, or non-ASCII characters with a named HTML entity) are replaced by their corresponding named character references.

```scheme
(html-escape "5 < 7 & 7 > 5")
⇒ "5 &lt; 7 &amp; 7 &gt; 5"
```

**(html-tag->string&#x20;*****tag attrs*****)** \[procedure]

Returns a string with the opening tag for element name *tag* (a symbol) with attribute list *attrs*. *attrs* is a list of `(name value)` pairs, matching the representation used for the `@` attribute list of an SXML element. If an attribute is given as an improper pair `(name . #f)`, it is rendered as a boolean attribute, i.e. just its name is written without a value. Attribute values are HTML-escaped.

```scheme
(html-tag->string 'input '((type "checkbox") (checked "checked") (disabled . #f)))
⇒ "<input type=\"checkbox\" checked=\"checked\" disabled>"
```
