Alpha. Vary is under active development and not ready for production use. Syntax, APIs, performance, and behaviour may change between releases.
xml
import xml owns escaping for XML and Atom feed output. The helpers
build elements, attributes, and documents from values, so application
code does not concatenate raw markup.
The StructuredMarkupStringRule (VCS001) flags string-assembled
markup; this module is what new code should use.
Elements and attributes
import xml
let attrs = [xml.xml_attr("href", "https://example.com/atom"),
xml.xml_attr("rel", "self")]
let link = xml.xml_empty_element("link", attrs)
let title = xml.xml_text_element("title", xml.xml_attrs(), "Issue updates")
| Helper | Purpose |
|---|---|
xml_attr(name, value) | Build a XmlAttribute (value escaped at emit time). |
xml_attrs() | Empty attribute list (cheap constructor). |
xml_element(name, attrs, body) | <name ...>body</name>; body is already-built XML. |
xml_text_element(name, attrs, value) | <name ...>escaped text</name>. |
xml_empty_element(name, attrs) | <name ... /> self-closing form. |
xml_document(root) | Prepends the standard XML declaration. |
Escaping
The escaping helpers are public so handlers that build a custom feed can still rely on the module's escape rules:
| Helper | Escapes |
|---|---|
xml_escape_text(value) | &, <, > for element text. |
xml_escape_attr(value) | &, <, >, " for attribute values. |
xml_name_valid(name) | False if the name has whitespace or <>/" characters. |
xml_element and xml_empty_element reject invalid names by returning
an empty string. Treat that as a bug in the caller, not a runtime
fallback: a bad name means the application built a tag from untrusted
data, and the right fix is to validate that input first.
Feed construction
import xml
let entries = []
for row in rows {
let title = xml.xml_text_element("title", xml.xml_attrs(), row.title)
let id = xml.xml_text_element("id", xml.xml_attrs(), row.id)
let updated = xml.xml_text_element("updated", xml.xml_attrs(), row.updated_at)
let entry = xml.xml_element("entry", xml.xml_attrs(), title + id + updated)
entries.append(entry)
}
let feed_body = title_element + link_element + entries.join("")
let feed = xml.xml_element("feed",
[xml.xml_attr("xmlns", "http://www.w3.org/2005/Atom")],
feed_body)
return xml.xml_document(feed)
Avoiding string-built markup
Do not concatenate raw < and > to build elements; the boundary's
markup check rule will flag it, and one missed escape leaks the value as
markup. If the helpers in this module do not cover a tag your feed
needs, add a new helper here and use it - do not work around the rule
locally.