Expand description
XML save-context API (upstream xmlsave.c, 2.15.3).
xmlSaveToFd / xmlSaveToFilename / xmlSaveToBuffer / xmlSaveToIO
create a save context; xmlSaveDoc / xmlSaveTree serialize into it;
xmlSaveFlush / xmlSaveClose / xmlSaveFinish finalize it.
§UPSTREAM-PARITY
xmlSaveCtxt is opaque in the public headers (xmlsave.h); the candidate
defines its own internal representation — there is no ABI constraint on
its layout. Behavior mirrors xmlsave.c: options XML_SAVE_FORMAT,
XML_SAVE_NO_DECL, XML_SAVE_NO_EMPTY and the deprecated escape callbacks.
Formatting/decl handling is provided by the tree serializer
(serialize_node_opts), which mirrors upstream xmlSaveDoc/
xmlSaveTree/DumpState mechanics.
§Courts
SAVE-* differential cases compare xmlSave* output byte-for-byte with
the oracle DSO across option combinations.
§Upstream contract
Mirrors upstream xmlsave.c (+ xmlIO.c output buffers) at libxml2
2.15.3 (SRC-LIBXML2-2.15.0-XMLSAVE-C): xmlSaveToFd / xmlSaveToIO /
xmlSaveToFilename / xmlSaveToBuffer, xmlSaveDoc, xmlSaveTree,
xmlSaveFlush / xmlSaveFinish / xmlSaveClose, and the deprecated
xmlSaveSetEscape / xmlSaveSetAttrEscape hooks.
§Conceptual behavior
A save context wraps an output buffer plus the XML_SAVE_* option mask;
xmlSaveDoc/xmlSaveTree delegate to the tree serializer
(serialize_node_opts), which mirrors upstream DumpState mechanics
(format/indent, XML declaration suppression, empty-element policy).
§Ownership & safety invariants
xmlSaveTo* adopts the output buffer; xmlSaveClose flushes and frees
it. The escape/attrEscape callback slots are stored verbatim and never
dereferenced by the context (deprecated upstream).
§Historical quirks & epochs
The escape/attrEscape hooks are deprecated since the 2.x era and kept only for source compatibility; the serializer behavior targets the 2.15.3 epoch (e.g. the html-dump single-line epoch E-007 applies to the HTML serializer, and XSLT output relies on these options).
§Deliberate oddities
xmlSaveCtxt is opaque in the public header, so the candidate-internal
layout is unconstrained — the deliberate fidelity surface is the
behavior, not the struct bytes.
§Proving courts
SAVE-* differential probes (courts/suites/data-abi/*) compare output byte-identical against the oracle DSO; the CLI differential courts (xmllint save paths) and cargo test round-trips cover the options.
§Tempting simplifications that would break parity
Do not drop the deprecated escape callback slots: consumers still set
them and observe them firing during serialization. Do not bypass the
output-buffer layer (xmlIO.c): flush counts and encoder interaction
(R-000151) are observable through xmlSaveFlush/xmlSaveClose.
Structs§
- _xml
Save Ctxt - Candidate-internal save context (opaque upstream).
Constants§
- XML_
SAVE_ AS_ HTML - Candidate-internal: nokogiri passes
SaveOptions::AS_HTML(64) to emit HTML-style output (HTML-void elements stay<br>-style, non-void empty elements get an explicit end tag). Mirrors nokogiri’s flag value, which is 64 (2^6); upstream usesXML_SAVE_AS_HTML = (1<<10). - XML_
SAVE_ FORMAT - XML_SAVE_FORMAT — format output (newlines + indentation).
- XML_
SAVE_ NO_ DECL - XML_SAVE_NO_DECL — don’t emit an XML declaration.
- XML_
SAVE_ NO_ EMPTY - XML_SAVE_NO_EMPTY — don’t emit empty tags.
Functions§
- xmlSave
Close ⚠ int xmlSaveClose(xmlSaveCtxt *ctxt)— flush, close and free the context.- xmlSave
Doc ⚠ - Serialize
docinto the save context’s output buffer. - xmlSave
File ⚠To int xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding)— upstream xmlsave.c delegates to xmlSaveFormatFileTo(buf, cur, encoding, 0).- xmlSave
Finish ⚠ xmlParserErrors xmlSaveFinish(xmlSaveCtxt *ctxt)— flush, close, free; returns an xmlParserErrors code (XML_ERR_OK on success).- xmlSave
Flush ⚠ int xmlSaveFlush(xmlSaveCtxt *ctxt)— flush the output buffer.- xmlSave
Format ⚠File To int xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format)— serializecurinto an existing output buffer and close it (upstream xmlsave.c).- xmlSave
SetAttr ⚠Escape int xmlSaveSetAttrEscape(xmlSaveCtxt *ctxt, xmlCharEncodingOutputFunc escape).- xmlSave
SetEscape ⚠ int xmlSaveSetEscape(xmlSaveCtxt *ctxt, xmlCharEncodingOutputFunc escape).- xmlSave
SetIndent ⚠String int xmlSaveSetIndentString(xmlSaveCtxt *ctxt, const char *indent).- xmlSave
ToBuffer ⚠ xmlSaveCtxt *xmlSaveToBuffer(xmlBuffer *buffer, const char *encoding, int options).- xmlSave
ToFd ⚠ xmlSaveCtxt *xmlSaveToFd(int fd, const char *encoding, int options).- xmlSave
ToFilename ⚠ xmlSaveCtxt *xmlSaveToFilename(const char *filename, const char *encoding, int options).- xmlSave
ToIO ⚠ xmlSaveCtxt *xmlSaveToIO(xmlOutputWriteCallback iowrite, xmlOutputCloseCallback ioclose, void *ioctx, const char *encoding, int options).- xmlSave
Tree ⚠ - Serialize a node tree into the save context’s output buffer.