AxlXml — XML
Streaming XML writer + pull-token reader. See AxlData — Data Structures for an overview of all data modules including the XML writer/reader pair.
Header: <axl/axl-xml.h>
API Reference
Defines
-
AXL_XML_WRITER_MAX_DEPTH
Maximum open-tag nesting the writer’s balance stack tracks. Exceeding this sets the sticky error flag.
Typedefs
-
typedef struct AxlXmlReader AxlXmlReader
Forward decl — opaque type.
Enums
-
enum AxlXmlWriterFlags
axl-xml.h:
Streaming XML writer + pull-token reader. Caller-managed namespaces: the writer treats qnames like
D:multistatusas opaque strings; namespace declarations are normal attributes. The reader returns one token at a time — START_ELEMENT, END_ELEMENT, TEXT, END_DOCUMENT — and attribute lookup is via axl_xml_reader_attr while positioned at a START_ELEMENT.Out of scope (intentional): DTD validation, schema validation (XSD / RelaxNG), XPath, XSLT, XML signatures. UTF-8 only.
Two independent APIs:
AxlXmlWriter — build XML into an AxlString
AxlXmlReader — pull tokens from an XML buffer AxlXmlWriterFlags:
Flags passed to axl_xml_writer_init.
Values:
-
enumerator AXL_XML_WRITER_DEFAULT
compact output (no indent / no newlines)
-
enumerator AXL_XML_WRITER_PRETTY
2-space indent + newlines between elements
-
enum AxlXmlTokenType
AxlXmlTokenType:
Discriminator for AxlXmlToken. END_DOCUMENT is delivered once after the last element closes; subsequent axl_xml_reader_next calls return false.
Values:
-
enumerator AXL_XML_TOKEN_START_ELEMENT
<qname ...>(or self-closing<qname/>)
-
enumerator AXL_XML_TOKEN_END_ELEMENT
</qname>(or self-closing pair)
-
enumerator AXL_XML_TOKEN_TEXT
body text or CDATA section content
-
enumerator AXL_XML_TOKEN_END_DOCUMENT
no more tokens
-
enumerator AXL_XML_TOKEN_START_ELEMENT
Functions
-
void axl_xml_writer_init(AxlXmlWriter *w, AxlString *out, uint32_t flags)
Initialize a writer.
The writer appends to
out— it does not clear it. To reuse a string between writes, the caller calls axl_string_clear before init.- Parameters:
w – writer to initialize
out – destination string (caller-owned)
flags – AxlXmlWriterFlags bitmask
-
size_t axl_xml_writer_finish(AxlXmlWriter *w)
Finalize the writer.
Validates that all opened elements were closed; sets the sticky error flag if not. Frees any heap state the writer still owns (tag stack entries). NULL-safe.
- Parameters:
w – writer (NULL-safe)
- Returns:
the length of
outafter this writer’s calls. (Equal to the bytes written iff the AxlString was empty at axl_xml_writer_init; otherwise includes any pre-existing content.)
-
bool axl_xml_writer_error(const AxlXmlWriter *w)
Query the sticky error flag.
Set on AxlString OOM, structural misuse (close-without-start, close-of-wrong-tag, stack overflow), or write-after-finish. Once set, all subsequent writer calls become no-ops.
- Parameters:
w – writer
- Returns:
true if any error occurred since init.
-
void axl_xml_writer_prologue(AxlXmlWriter *w)
Emit the XML prologue:
<?xml version="1.0" encoding="UTF-8"?>.Must be the first emit call after init (writer is otherwise unconstrained — prologue is optional). Calling it after any element-emitting call sets the sticky error flag.
- Parameters:
w – writer
-
void axl_xml_writer_doctype(AxlXmlWriter *w, const char *root, const char *dtd_uri)
Emit a DOCTYPE declaration:
<!DOCTYPE root SYSTEM "dtd_uri">.dtd_urimay be NULL to emit a bare<!DOCTYPE root>. Must appear before the first element start; later calls set the sticky error flag. Neitherrootnordtd_uriis escaped — caller is responsible for providing values legal in those positions (no<>"&).- Parameters:
w – writer
root – root element name
dtd_uri – DTD system URI (NULL → bare DOCTYPE)
-
void axl_xml_writer_start_element(AxlXmlWriter *w, const char *qname)
Open an element:
<qname.The element stays “open” —
axl_xml_writer_attributecalls add attributes, then the start tag is auto-closed (<qname ...>) on the first child / text / end. Nesting limit:AXL_XML_WRITER_MAX_DEPTH.qnameis treated as opaque (writer does not split namespace prefix from local name) and is NOT escaped — caller is responsible for the name being legal in tag position. Caller also manages namespace declarations via axl_xml_writer_attribute (e.g. attrxmlns:D="DAV:").- Parameters:
w – writer
qname – element qname (NUL-terminated)
-
void axl_xml_writer_attribute(AxlXmlWriter *w, const char *name, const char *value)
Add an attribute to the currently-open start tag.
Only valid between axl_xml_writer_start_element and the next text/child/end call. Calling outside that window — or with an empty
name— sets the sticky error flag.valueis auto-escaped for&<".nameis NOT escaped; caller provides a legal attribute name.- Parameters:
w – writer
name – attribute name
value – attribute value (escaped)
-
void axl_xml_writer_text(AxlXmlWriter *w, const char *text)
Emit body text content for the current element.
Auto-escapes
&<>. Multiple text calls between a start and end concatenate. NUL-terminated input variant. An emptytextis a silent no-op (the element may still self-close as<foo/>at axl_xml_writer_end_element); to force<foo></foo>, omit the empty text call entirely — the difference is purely stylistic since<foo/>and<foo></foo>are XML-equivalent.- Parameters:
w – writer
text – NUL-terminated text
-
void axl_xml_writer_textn(AxlXmlWriter *w, const char *text, size_t n)
Length-counted variant of axl_xml_writer_text. Allows emitting non-NUL-terminated slices of a larger buffer.
- Parameters:
w – writer
text – text bytes
n – byte count
-
void axl_xml_writer_end_element(AxlXmlWriter *w)
Close the most recently opened element.
Emits
</qname>(or/>if the element has no body content). Order is enforced: closing an element when the stack top doesn’t match implies a caller-side balance bug — the writer can’t detect “wrong tag” because the closer doesn’t name it, but close-without-start does set the sticky error flag.- Parameters:
w – writer
-
AxlXmlReader *axl_xml_reader_new(const char *buf, size_t len)
Create a reader over
buf.The reader references
buf— caller must keep the buffer alive until axl_xml_reader_free. NUL terminator not required. Returns NULL on OOM.- Parameters:
buf – XML bytes
len – byte count
-
bool axl_xml_reader_next(AxlXmlReader *r, AxlXmlToken *out)
Pull the next token.
On success, fills
outwith the next token’s data and returns true. On parse error or after END_DOCUMENT was delivered, returns false; call axl_xml_reader_error to distinguish.The reader yields START_ELEMENT, END_ELEMENT, TEXT, and a single END_DOCUMENT after the last close. XML declaration (
<?xml ?>), processing instructions, comments, and DOCTYPE declarations are skipped silently. CDATA section content arrives as a TEXT token withis_cdataset.- Parameters:
r – reader
out – [out] filled on success
-
const char *axl_xml_reader_attr(AxlXmlReader *r, const char *name)
Look up an attribute on the current START_ELEMENT.
Valid between a successful axl_xml_reader_next that returned a START_ELEMENT and the next axl_xml_reader_next call. Returns NULL if the attribute isn’t present, the reader is not positioned at a START_ELEMENT, or
nameis NULL. The returned pointer references reader-owned storage and is valid until the next axl_xml_reader_next.- Parameters:
r – reader
name – attribute name (NUL-terminated)
-
bool axl_xml_reader_error(const AxlXmlReader *r, uint32_t *line, uint32_t *col, const char **msg)
Retrieve error details after a false return from axl_xml_reader_next.
Each out-param is optional (NULL skips). After clean EOF (
AXL_XML_TOKEN_END_DOCUMENTwas the last delivered token), returns false with no error message. After a parse error, returns true and fills line / column / message.- Parameters:
line – [out, optional] 1-based line of the error
col – [out, optional] 1-based column of the error
msg – [out, optional] static error message
- Returns:
true iff a parse error has occurred.
-
void axl_xml_reader_free(AxlXmlReader *r)
Free the reader (NULL-safe).
Releases heap state. Does NOT free the input buffer.
- Parameters:
r – reader (NULL-safe)
-
const char *axl_xml_token_local_name(const AxlXmlToken *tok, size_t *out_len)
Return the local name (post-colon) of
tok'sqname.For a prefixed name like
D:response, returns a pointer toresponseand writes 8 intoout_len. For an unprefixed name likeresponse, returns the full name. The returned pointer aliases intotok'snameslice and is valid for the same lifetime (until the next axl_xml_reader_next).Defined only for START_ELEMENT and END_ELEMENT tokens. On TEXT / END_DOCUMENT (or NULL inputs) returns NULL with
*out_len= 0.- Parameters:
out_len – [out] local-name byte length (NULL OK)
-
bool axl_xml_token_local_name_eq(const AxlXmlToken *tok, const char *want)
Compare
tok'slocal name to a NUL-terminated literal.Convenience predicate folding the local-name extract + memcmp. Returns false for TEXT / END_DOCUMENT tokens, NULL inputs, or length / byte mismatches.
-
struct AxlXmlWriter
- #include <axl-xml.h>
Streaming XML writer that builds into a caller-owned AxlString. Element start / attribute / text / end are independent calls; the state machine tracks open-tag depth so closes can’t outrun starts. Auto-escapes
&<>in text, plus"in attribute values. Fields are private — use accessors.Errors are sticky: once any call detects a structural misuse (close-without-start, stack overflow, attribute-after-content, prologue / doctype after first element) or the backing AxlString fails to grow, every subsequent call is a no-op. Check via axl_xml_writer_error at finish.
Public Members
-
uint32_t flags
AxlXmlWriterFlags.
-
uint32_t depth
current open-tag depth (0..MAX)
-
bool in_start_tag
inside
<foo, attrs/text/close pending
-
bool prologue_emitted
prologue may only be emitted once
-
bool doctype_emitted
doctype may only be emitted once
-
bool any_element_emitted
root element has been started
-
bool error
sticky error flag
-
uint64_t had_text_bits
bit i: depth-i element has body text
-
uint64_t had_child_bits
bit i: depth-i element has a child element
-
char *stack[64]
Tag-name stack: stack[i] is the qname of the element opened at depth i. strdup’d at start, freed at end. Used in pretty mode (where we need the name on the closing tag emit path) and the close-without-start guard.
-
uint32_t flags
-
struct AxlXmlToken
- #include <axl-xml.h>
One pulled token. String pointers reference into reader-owned storage and are valid only until the next axl_xml_reader_next call. Caller must copy out anything it needs to retain past that.
Public Members
-
AxlXmlTokenType type
-
const char *name
element qname (START / END only); NULL otherwise
-
size_t name_len
-
const char *ns_uri
Resolved namespace URI for this element (START / END only). NULL when no xmlns binding is in scope. The reader maintains an internal xmlns binding stack: a prefixed qname (e.g.
D:foo) resolves against the nearest enclosingxmlns:D=declaration; an unprefixed name resolves against the nearest enclosingxmlns=(default-namespace) declaration. Use axl_xml_token_local_name to extract the post-colon part.Known limitations (lenient v1; tighten when a consumer asks):
The reserved
xml:prefix is NOT implicitly bound to. Elements like<xml:lang>without an explicitxmlns:xml=declaration resolve to NULL ns_uri.xmlns=""(the empty-string undeclare-default-ns form per Namespaces 1.0 errata) is honored: subsequent unprefixed children resolve to NULL ns_uri, not “”.
-
size_t ns_uri_len
-
const char *text
text bytes (TEXT only); NULL otherwise
-
size_t text_len
-
bool is_cdata
TEXT only: true iff token came from
<![CDATA[ ... ]]>
-
AxlXmlTokenType type