How-to guides/XFA Forms

Parse and fill XFA dynamic forms in Rust

XFA forms are embedded XML applications inside a PDF. PDFluent can parse the XFA data packet, read field values, and write new values back to the document.

Not in the current release. This capability is not part of the published PDFluent SDK; the example below does not compile against the current release. See the changelog for what ships today.
rust
use pdfluent::{PdfDocument, XfaForm};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("dynamic-form.pdf")?;
    let mut form = doc.xfa_form_mut()?;

    form.set_field("EmployeeName", "Ada Lovelace")?;
    form.set_field("EmployeeId", "EMP-1815")?;
    form.set_field("Department", "Engineering")?;

    doc.save("filled-form.pdf")?;
    Ok(())
}

Step by step

1

Add PDFluent with the xfa feature

XFA support is in the xfa feature flag. It includes the XML parser and the XFA data packet writer.

rust
# Cargo.toml
[dependencies]
pdfluent = { version = "0.9", features = ["xfa"] }
2

Open the PDF and check for an XFA form

Not every PDF contains an XFA form. Use has_xfa() to check before calling xfa_form().

rust
use pdfluent::PdfDocument;

let doc = PdfDocument::open("dynamic-form.pdf")?;

if doc.has_xfa() {
    println!("XFA form detected");
} else {
    println!("No XFA form found in this document");
}
3

Enumerate all form fields

Call xfa_form() to get a read-only view. Iterate fields() to discover field names and their current values.

rust
let form = doc.xfa_form()?;

for field in doc.form_fields() {
    println!(
        "name={:?}  type={:?}  value={:?}",
        field.name(),
        field.field_type(),
        field.value()
    );
}
4

Set field values

Use xfa_form_mut() to get a mutable handle. set_field() accepts any value that implements Into<String>.

rust
let mut form = doc.xfa_form_mut()?;

form.set_field("EmployeeName", "Ada Lovelace")?;
form.set_field("StartDate", "2024-03-01")?;
form.set_field("FullTime", "true")?;   // checkbox
5

Save the filled document

Save writes the updated XFA data packet back into the PDF structure. The output is a valid PDF with the new field values baked in.

rust
doc.save("filled-form.pdf")?;
println!("Saved filled-form.pdf");

Notes and tips

  • XFA forms come in two variants: static XFA and dynamic XFA. PDFluent supports both for reading. Dynamic XFA reflow is supported for simple layouts.
  • XFA forms were deprecated in PDF 2.0. Many modern viewers have dropped support. Consider converting to AcroForm for maximum compatibility.
  • Field names in XFA are XPath expressions. Short names like "EmployeeName" work for flat forms. Nested subforms require a full path like "Root.PersonData.Name".
  • PDFluent preserves all XFA streams not modified by set_field(), so signature fields and static content are not affected.

Why PDFluent for this

Pure Rust

No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.

Memory safe

Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.

Runs anywhere

Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.

Frequently asked questions