Skip to content

XFA 表单 — Python / Rust / Node.js / Go / C#

检测与分析 XFA 表单——目前唯一直接读取 XML 模板、不依赖 AcroForm 回退的 PDF 库:

from pdf_oxide import PdfDocument

doc = PdfDocument("government-form.pdf")
xfa = doc.analyze_xfa()
if xfa:
    print(f"XFA form with {len(xfa.fields)} fields")
    for field in xfa.fields:
        print(f"  {field.name}: {field.field_type}")

XFA(XML Forms Architecture)是一种旧版表单格式,被许多政府机构、金融机构和企业系统广泛使用。大多数 Python PDF 库完全无法处理 XFA 表单。PDF Oxide 可以检测、分析并从中提取数据。

什么是 XFA?

XFA 表单使用嵌入在 PDF 内部的基于 XML 的模板,而非标准的 AcroForm 字段。它们由 Adobe 创建,常见于:

  • 政府表单 — IRS、移民、州政府机构文件
  • 金融表单 — 贷款申请、保险理赔
  • 企业表单 — HR 入职、采购、合规

XFA 在 PDF 2.0(ISO 32000-2:2020)中已被废弃,但数百万现有 XFA 文档仍在流通中。

XFA vs AcroForm

特性 AcroForm XFA
格式 PDF 对象 XML 模板
支持者 所有 PDF 库 极少数 PDF 库
动态布局 不支持 支持
PDF 2.0 状态 支持 已废弃
典型来源 大多数表单创建工具 Adobe LiveCycle、Adobe Designer

为什么 PyMuPDF 和 pypdf 无法处理 XFA 表单

如果你尝试用流行的 Python PDF 库读取 XFA 表单,很可能看到空结果且没有错误或警告。这是因为 PyMuPDF、pypdf、pdfplumber 和 pdfminer 都没有 XFA 支持

PyMuPDF (fitz) — 静默返回空结果

PyMuPDF 的 doc.get_form_fields() 和页面 .widgets() 只读取 AcroForm 字段。当 PDF 使用 XFA 独有表单(在 IRS、移民和州政府机构文件中很常见)时,PyMuPDF 返回空结果且没有任何警告:

# PyMuPDF — 静默丢失 XFA 数据
import fitz
doc = fitz.open("government-form.pdf")
fields = doc[0].widgets()  # 在 XFA 独有表单上返回 []
form_data = doc.get_form_fields()  # 在 XFA 独有表单上返回 {}

如果 XFA 表单包含 AcroForm 回退层,PyMuPDF 可能返回部分字段子集——但实际的 XFA 数据(动态布局、计算值、嵌套子表单)是不可见的。

pypdf — 同样在 XFA 表单上返回空结果

pypdf 的表单字段读取有同样的限制。它只能访问 AcroForm 字段,不支持 XFA:

# pypdf — 无法读取 XFA 内容
from pypdf import PdfReader
reader = PdfReader("government-form.pdf")
fields = reader.get_form_text_fields()  # 在 XFA 独有表单上返回 {}

pdfplumber 和 pdfminer — 完全不支持 XFA

pdfplumber 和 pdfminer 不尝试从 XFA 表单读取字段。它们没有用于 XFA 检测或提取的 API。

PDF Oxide — 原生读取 XFA

PDF Oxide 直接解析 XFA XML 模板,提取所有字段、值和表单结构:

# PDF Oxide — 原生读取 XFA
from pdf_oxide import PdfDocument
doc = PdfDocument("government-form.pdf")
xfa = doc.analyze_xfa()
print(f"{len(xfa.fields)} fields found")  # 所有 XFA 字段已提取

这适用于政府表单、IRS 文件、保险申请以及任何基于 XFA 的 PDF——包括没有 AcroForm 回退层的表单。

安装

pip install pdf_oxide

检测 XFA 表单

检查 PDF 是否包含 XFA 内容:

Python

from pdf_oxide import PdfDocument

doc = PdfDocument("form.pdf")
xfa = doc.analyze_xfa()

if xfa:
    print("This PDF uses XFA forms")
    print(f"  Fields: {len(xfa.fields)}")
    print(f"  Has template: {xfa.has_template}")
    print(f"  Has datasets: {xfa.has_datasets}")
else:
    print("Standard AcroForm (or no forms)")

WASM

在 WASM 中,你可以检测 XFA 表单并回退到读取 AcroForm 字段:

import { WasmPdfDocument } from "pdf-oxide-wasm";

const doc = new WasmPdfDocument(bytes);
if (doc.hasXfa()) {
  console.log("This PDF uses XFA forms");
  // 读取 AcroForm 回退字段
  const fields = doc.getFormFields();
  console.log(`AcroForm fallback fields: ${fields.length}`);
}
doc.free();

分析 XFA 字段

获取 XFA 表单中每个字段的详细信息:

from pdf_oxide import PdfDocument

doc = PdfDocument("tax-form.pdf")
xfa = doc.analyze_xfa()

if xfa:
    for field in xfa.fields:
        print(f"Name: {field.name}")
        print(f"  Type: {field.field_type}")
        print(f"  Value: {field.value}")
        print()

读取 XFA 数据

从 XFA 数据集中提取当前字段值:

from pdf_oxide import PdfDocument

doc = PdfDocument("filled-xfa.pdf")
xfa = doc.analyze_xfa()

if xfa and xfa.has_datasets:
    data = {}
    for field in xfa.fields:
        if field.value:
            data[field.name] = field.value
    print(data)

批量处理 XFA 表单

扫描一个目录以识别哪些 PDF 使用了 XFA:

from pdf_oxide import PdfDocument, PdfError
from pathlib import Path

pdf_dir = Path("government-forms/")
xfa_files = []
acroform_files = []

for pdf_path in pdf_dir.glob("*.pdf"):
    try:
        doc = PdfDocument(str(pdf_path))
        xfa = doc.analyze_xfa()
        if xfa:
            xfa_files.append(pdf_path.name)
        else:
            acroform_files.append(pdf_path.name)
    except PdfError as e:
        print(f"Error: {pdf_path.name}: {e}")

print(f"XFA forms: {len(xfa_files)}")
print(f"Standard forms: {len(acroform_files)}")

Rust API

use pdf_oxide::PdfDocument;
use pdf_oxide::xfa::analyze_xfa_document;

let mut doc = PdfDocument::open("xfa-form.pdf")?;
let analysis = analyze_xfa_document(&mut doc)?;

println!("XFA form detected: {} fields", analysis.fields.len());
for field in &analysis.fields {
    println!("  {} ({:?}): {:?}", field.name, field.field_type, field.value);
}

为什么 XFA 很重要

大多数 Python PDF 库静默忽略 XFA 内容——extract_text() 和表单字段 API 只能看到 AcroForm 回退层(如果存在的话)。许多 XFA 独有的表单没有 AcroForm 回退,使得它们对其他工具完全不可见:

  • PyMuPDF (pymupdf) XFA 表单get_form_fields().widgets() 在 XFA 独有 PDF 上返回空。PyMuPDF 没有 XFA 支持,也没有添加的计划。
  • pypdf XFA 支持 — pypdf 的 get_form_text_fields() 无法读取 XFA 内容。只有 AcroForm 回退字段可见——如果它们存在的话。
  • pdfplumber — 不支持 XFA。表单提取仅限于 AcroForm 字段。
  • pdfminer — 不支持 XFA。无法检测或提取 XFA 表单数据。

PDF Oxide 是唯一直接读取 XFA XML 模板的 Python PDF 库,让你可以访问 PyMuPDF、pypdf、pdfplumber 和 pdfminer 都看不到的表单结构和数据。

相关页面