Skip to main content

Module io

Module io 

Source
Expand description

Custom input callbacks for xmlRegisterInputCallbacks — bundle XSLT stylesheets / RNG schemas inside the binary and serve them through a user-defined URL scheme (e.g. embed:///foo.xsl). Custom I/O callbacks for libxml2.

libxml2 routes every URL it loads (XML documents, xsl:import / xsl:include targets, RelaxNG <include>, DTD external subsets, etc.) through a chain of registered “input callback” handlers. The default chain handles file://, http://, ftp://, etc.; an application can prepend its own handler for a custom URL scheme via xmlRegisterInputCallbacks.

This module wraps that C API in a safe, closure-friendly surface. The motivating use case is shipping a single-binary CLI that bundles XSLT stylesheets / RNG schemas via include_bytes! and serves them through a synthetic scheme (e.g. embed:///foo.xsl), so xsl:import chains resolve without ever touching the disk.

use libxml::io;

static MAIN: &[u8] = b"<?xml version=\"1.0\"?>\n<root/>";

io::register_input_callback(
  |url| url.starts_with("embed:///"),
  |url| match url.strip_prefix("embed:///") {
    Some("main.xml") => Some(MAIN.to_vec()),
    _ => None,
  },
);

§Lifetime, threading, order

Closures live for the process lifetime — libxml2 has no per-handler unregister API. They may run on any thread (hence Send + Sync) and must not panic: unwinding across the extern "C" trampoline aborts on Rust 2024+. libxml2 walks callbacks newest-first; the trampolines snapshot the registry and drop the lock before invoking a user closure, so a closure that re-enters libxml2 won’t self-deadlock. If open returns None, libxml2 falls through to the next handler — including its default file/HTTP loaders.

Functions§

register_input_callback
Register a custom input callback with libxml2.