adf
Lightweight Rust parsing and writing for Auto-lead Data Format (ADF) 1.0 XML leads.
This crate is aimed at low-overhead ADF processing:
- parses XML with
quick-xml - borrows input text where possible through
Cow<'a, str> - exposes a typed ADF model for common lead fields
- keeps unknown XML elements and attributes — on containers and compact elements alike — instead of discarding partner data
- preserves CDATA wrappers and unknown entity references through the typed writer
- can write the original document byte-for-byte when it has not been changed
- can rewrite only dirty prospect spans for localized edits
- keeps ADF-specific validation separate from XML parsing, with optional strict mode plus DTD enum and ISO format checks
- never resolves external entities or expands custom ones, and bounds (or rejects)
<!DOCTYPE>declarations to keep untrusted input safe
Installation
[]
= "0.4"
Example
use parse;
use Cow;
Writing Modes
AdfDocument::to_original_preserving_string() preserves the original XML when the document is clean. If a single prospect is modified through prospect_mut, only that prospect's original byte span is rewritten and the surrounding XML is copied through unchanged.
AdfDocument::to_typed_string() writes normalized ADF XML from the typed model. This is useful when broad structural edits are made through adf_mut, or when normalized output is preferred over preserving original formatting.
AdfDocument::root() exposes the raw XML tree for callers that need it. The tree is parsed lazily on first access so typed-only processing does not retain both the full raw tree and the typed ADF model.
Parsing Safety
The parser never resolves external entities and never expands custom (DTD-defined) entities: only the five predefined XML entities and numeric character references are substituted, and any other reference is preserved verbatim. This makes classic XXE and entity-expansion ("billion laughs") attacks structurally impossible.
parse keeps <!DOCTYPE> declarations so partner documents round-trip, but caps the internal subset at DEFAULT_MAX_DOCTYPE_LEN (4096 bytes) by default. Use parse_with and ParseOptions to tighten or relax this:
use ;
Validation
Parsing only requires well-formed XML. ADF-specific checks are available through AdfDocument::validate():
The default validator reports DTD-required elements as warnings, checks DTD enumerated attribute values (prospect@status, vehicle@interest, price@type, etc.), and warns on malformed ISO 8601 dates, ISO 4217 currency codes, and ISO 3166 country codes.
AdfDocument::validate_strict() (or validate_with(adf, ValidationOptions::default().strict(true))) promotes the "missing required element" warnings to errors, suitable for gating on conformance.
Logging and Tracing
adf emits passive tracing spans and events for parse, validation, and write operations. The crate does not install a subscriber; applications decide whether and how to collect those events.
Trace fields are limited to structural metadata such as byte counts, parse options, model counts, dirty flags, validation issue counts, and error categories/positions. They intentionally do not include raw XML, element text, attribute values, validation messages, names, emails, phone numbers, addresses, identifiers, URLs, comments, or extension payloads.
The public model and AdfDocument::original() still expose lead payloads; avoid logging those values directly when handling sensitive data.
License
Licensed under either of:
- Apache License, Version 2.0
- MIT license
at your option.
Development