----
title: XEXPR module – handling XML as scheme s-expressions
SPDX-FileCopyrightText: 2024 Norman Gray <https://nxg.me.uk>
SPDX-License-Identifier: BSD-2-Clause


Scheme s-expressions are a convenient way of wrangling XML, known as
x-expressions.  The functions in this module will search the content
of, and write out, such x-expressions.  There are a couple of ways
that x-expressions have been defined, in the Scheme world, in the
past.  I have followed
[Racket](https://docs.racket-lang.org/xml/index.html).

The following grammar describes expressions that create
X-expressions:

    xexpr = string
      | (list symbol (list (list symbol string) ...) xexpr ...)
      | (cons symbol (list xexpr ...))
      | symbol
      | valid-char?
      | cdata
      | misc

For example:

    (xexpr-write/xml!
       '(p "Here is a " (a ((href "http://foo")) "link")
           " with " (br ((clear "right")))
           ". This" amp "that" 33))

produces

    <p>Here is a <a href="http://foo">link</a> with <br clear="right" />. This&amp;that&#x21;</p>

Above, a ‘string’ is literal data, either as a `"string"` or `#[ustring]`.
When converted to an XML stream, the
characters of the data will be escaped as necessary.

A pair represents an element, optionally with attributes. Each
attribute’s name is represented by a symbol, and its value is
represented by a string.

A symbol represents an entity reference.  For example, the symbol `'nbsp`
represents `&nbsp;`.  These are serialised as such, _unless_
`:expand-entities?` is `#t`, in which case _a subset_ of entities are
expanded into the nominated character.  It is unspecified just what
entities are included in this ‘subset’, but
[this list](https://developer.mozilla.org/en-US/docs/Glossary/Entity) is reasonable.

A `valid-char?` represents a numeric entity. For example, `#x20` represents `&#x20;`.

Right now, I don't implement cdata or misc.

There is not at present any support for parsing XML into xexprs.

Writing
-------

The functions
[`xexpr-write/md!`](#fn-xexpr-write/md!),
[`xexpr-write/python!`](#fn-xexpr-write/python!),
[`xexpr-write/sexp!`](#fn-xexpr-write/sexp!),
[`xexpr-write/xhtml!`](#fn-xexpr-write/xhtml!),
[`xexpr-write/xml!`](#fn-xexpr-write/xml!)
will write out an xexpr in one or other format
(the function `xexpr-write/xhtml!` is generally the most useful).

Examining
---------

The function
[`xexpr-path-search`](#fn-xexpr-path-search) implements a basic path
searcher.

Given an xexpr, functions
[`xexpr-disassemble`](#fn-xexpr-disassemble),
[`xexpr-get-attribute`](#fn-xexpr-get-attribute) and
[`xexpr-text`](#fn-xexpr-text) make it convenient to inspect the contents.
