Getting started
Requirements
a C99 compiler;
CMake 3.16 or newer;
Python 3 to run
zxsdcand the tests.
Prefer a compiler/runtime pair from the same release. On upgrades, follow API, ABI, and migration: legacy unversioned output must be regenerated, and all 0.x consumers must be rebuilt with matching memory limits and ABI flags.
Build and test the runtime
Linux and macOS:
$ cmake -S . -B build -DZXSD_USE_MXML=OFF
$ cmake --build build
$ ctest --test-dir build --output-on-failure
Windows PowerShell with Visual Studio Build Tools:
cmake -S . -B build -DZXSD_USE_MXML=OFF
cmake --build build --config Release
ctest --test-dir build -C Release --output-on-failure
Compile a schema
Given device.xsd, generate a validator in generated:
$ ./zxsdc device.xsd -o generated
On Windows, invoke the extensionless script through Python:
python .\zxsdc device.xsd -o generated
The output contains device.zxsd.c and device.zxsd.h. The header exposes
the generated schema accessor and convenience validation functions. File and
symbol names are derived from the XSD filename.
Validate a complete document
#include <stdio.h>
#include "device.zxsd.h"
int main(void)
{
const char xml[] =
"<device id='7'><name>node</name><sample>1</sample></device>";
zxsd_result_t result = device_validate(xml);
if (result.code != ZXSD_OK) {
fprintf(stderr, "%s at byte %lu (schema item: %s)\n",
result.message, (unsigned long)result.offset,
result.path != NULL ? result.path : "unknown");
return 1;
}
return 0;
}
Compile the generated source together with the runtime, or use the supplied CMake helper to generate and compile it during the build:
find_package(zxsd CONFIG REQUIRED)
add_executable(application main.c)
zxsd_generate(TARGET application SCHEMA device.xsd)
target_link_libraries(application PRIVATE zxsd::zxsd)
Add BINDINGS to generate typed bindings. For composed schemas, pass files
reached through xs:include, xs:import, or xs:redefine to
DEPENDS so CMake regenerates the output when they change. Repeated
BIND_ROOT and SCHEMA_PATH arguments map to repeated compiler options;
MAX_SCHEMA_COMPLEXITY sets the compiler limit.
The installed package exports zxsd::zxsd, zxsd_generate(), and the
host zxsdc location. Set CMAKE_PREFIX_PATH to the installation prefix
when it is outside CMake’s normal search locations.
The complete cross-platform example in samples/host uses this helper:
$ cmake -S samples/host -B build-example -DZXSD_USE_MXML=OFF
$ cmake --build build-example
$ ./build-example/zxsd_example
Windows multi-configuration generators place the executable at
build-example\Release\zxsd_example.exe.
Consume parser events
The streaming API avoids retaining a complete XML document. Pass expanded names: the namespace URI and local name are separate, and text and attribute values must already be XML-decoded.
zxsd_stream_t stream;
zxsd_result_t result = device_stream_init(&stream);
if (result.code == ZXSD_OK)
result = zxsd_start_element(&stream, NULL, "device");
if (result.code == ZXSD_OK)
result = zxsd_attribute(&stream, NULL, "id", "7");
if (result.code == ZXSD_OK)
result = zxsd_start_content(&stream);
/* Send child start/text/end events in document order. */
if (result.code == ZXSD_OK)
result = zxsd_end_element(&stream, NULL, "device");
if (result.code == ZXSD_OK)
result = zxsd_stream_finish(&stream);
Every operation returns a sticky zxsd_result_t; stop sending events
after the first error. Resolve the QName value of xsi:type in the XML
frontend before calling zxsd_xsi_type().
Consume raw XML fragments
Use zxsd_xml_reader_t when a socket or HTTP client returns raw XML
in pieces. Fragment boundaries may occur anywhere in the document, and the
reader does not retain pointers into the input buffer.
zxsd_xml_reader_t reader;
zxsd_result_t result = zxsd_xml_reader_init(&reader, device_schema());
while (result.code == ZXSD_OK && receive_fragment(buffer, sizeof(buffer), &length))
result = zxsd_xml_reader_feed(&reader, buffer, length);
if (result.code == ZXSD_OK)
result = zxsd_xml_reader_finish(&reader);
zxsd_xml_reader_dispose(&reader);
The embedded validator preserves the event API’s sticky first error. Storage
for an incomplete XML token is fixed by ZXSD_XML_TOKEN_CAPACITY and decoded
text is bounded by ZXSD_MAX_TEXT_LENGTH.
Install an zxsd_xml_event_fn with
zxsd_xml_reader_set_event_callback() to copy a compact application
summary while the complete document continues to be validated.
Memory policy
Set ZXSD_NO_HEAP=ON for a zero-heap runtime. Schemas without identity
constraints then validate without allocation. Identity constraints require
bounded scratch storage and can use an application-owned
zxsd_allocator_t through
zxsd_validate_with_allocator().
All ZXSD_MAX_* values can be overridden at compile time. Exceeding a limit
returns a resource or streaming error; the runtime does not grow without a
bound. See Resource measurements for measured Cortex-M figures.