Write field values into the XFA datasets packet to populate a dynamic XFA form with application data.
use pdfluent::Document;
fn main() -> pdfluent::Result<()> {
let mut doc = Document::open("blank_form.pdf")?;
{
let xfa = doc.xfa_mut().ok_or(pdfluent::Error::NoXfa)?;
let mut datasets = xfa.datasets_mut()?;
datasets.set_field("form1.subform1.firstName", "Alice")?;
datasets.set_field("form1.subform1.lastName", "Dupont")?;
datasets.set_field("form1.subform1.dob", "1985-06-15")?;
}
doc.save("filled_form.pdf")?;
Ok(())
}Open the template form file for mutation. The XFA structure must already exist; PDFluent cannot create an XFA template from scratch.
let mut doc = Document::open("blank_form.pdf")?;xfa_mut() returns a mutable XFA handle. datasets_mut() parses the xfa:data XML into an editable tree.
let xfa = doc.xfa_mut().ok_or(pdfluent::Error::NoXfa)?;
let mut datasets = xfa.datasets_mut()?;Field paths are dot-separated, following the XFA form hierarchy. The path must match a node in the template.
datasets.set_field("form1.personal.firstName", "Alice")?;
datasets.set_field("form1.personal.lastName", "Dupont")?;
datasets.set_field("form1.personal.email", "[email protected]")?;For batch filling, pass a map of path -> value pairs.
use std::collections::HashMap;
let mut values: HashMap<&str, &str> = HashMap::new();
values.insert("form1.address.street", "123 Main St");
values.insert("form1.address.city", "Amsterdam");
values.insert("form1.address.postcode", "1234AB");
for (path, value) in &values {
datasets.set_field(path, value)?;
}The modified datasets XML is serialized back into the PDF. Save to a new file to preserve the original blank template.
doc.save("filled_form.pdf")?;No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.
Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.
Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.