A small regex-based XML reader for the UK list file. The document is split into record strings, and fields are read from each record with regexes: element text by tag, nested blocks, and attributes of start tags. Character references are decoded on the way out.
This is not a general XML parser. It relies on the file format: record elements do not nest inside themselves, field elements hold plain text, and there are no CDATA sections or comments inside records.
Why not ::hot::xml for the whole file. Speed. from-xml parses
22 MB in under a second, but every call that takes part of a parsed
tree copies it, and a record's fields take dozens of such calls.
Strings are cheap to pass. Measured on a real 22 MB list file (6,418
records) with a debug build: 55 s here, 91 to 109 s walking the tree,
with identical entries. Whole-tree parsing is worth revisiting if passing
a tree to a function stops copying it.
Functions
attr
fn (start-tag: Str?, name: Str): Str?
An attribute of a start tag string, decoded and trimmed, or null when missing or blank.
Example
::uk::sanctions::xml/attr("<nameAlias wholeName=\\"Abu Ali\\" strong=\\"true\\">", "wholeName") // "Abu Ali"
block
fn (fragment: Str?, tag: Str): Str?
The inner content of the first <tag> element, or null.
blocks
fn (fragment: Str?, tag: Str): Vec<Str>
The raw inner content of every <tag> element in fragment, in order (for nested structures).
clean
fn (s: Str): Str?
decode
fn (s: Str): Str
Decode XML character references in text with ::hot::xml: the five
named entities and numeric references (é, 
). &lt;
stays the literal text <. Text the parser refuses comes back as
it was.
Example
::uk::sanctions::xml/decode("Smith & Sons été") // "Smith & Sons été"
element-pattern
fn (tag: Str): Str
records
fn (doc: Str, tag: Str): Vec<Str>
Every <tag ...>...</tag> element of a document as a raw string.
The tag must not nest inside itself; <tag/> is skipped.
Example
::uk::sanctions::xml/records("<a><r>1</r><r>2</r></a>", "r") // ["<r>1</r>", "<r>2</r>"]
start-tags
fn (fragment: Str?, tag: Str): Vec<Str>
Every start (or empty-element) tag <tag .../> in fragment, as raw strings, for reading attributes.
text
fn (fragment: Str?, tag: Str): Str?
The text of the first non-blank <tag> element, or null.
texts
fn (fragment: Str?, tag: Str): Vec<Str>
The text of every <tag> element in fragment: references
decoded, whitespace runs collapsed, trimmed, blanks dropped. Use it
for elements that hold text only.
Example
::uk::sanctions::xml/texts("<n><v>A & B</v><v/><v> C </v></n>", "v") // ["A & B", "C"]