Hai biểu mẫu có thể mang cùng các trường nhưng hành xử hoàn toàn khác nhau. Một AcroForm giữ các trường của nó như các đối tượng PDF thông thường nằm trên nội dung trang thực, nên bất kỳ trình đọc tuân thủ nào cũng vẽ được nó. Một biểu mẫu XFA động giữ hầu như không có gì dưới dạng PDF: các trường, bố cục, thậm chí cả hình học trang đều sống trong một gói XML, và các trang có thể nhìn thấy được được tạo ra tại thời điểm mở bởi một engine bố cục mà chỉ Adobe từng phát hành rộng rãi. Đưa tệp đó cho một trình xem web, một trình kết xuất lưu trữ, hoặc một trình trích xuất văn bản và bạn sẽ không nhận được biểu mẫu. Bạn sẽ nhận được một trang xám duy nhất ghi "Vui lòng chờ... Nếu thông báo này cuối cùng không được thay thế bằng nội dung thực sự của tài liệu, trình xem PDF của bạn có thể không hiển thị được loại tài liệu này." Bất kỳ ai từng tiếp nhận giấy tờ của chính phủ hoặc bảo hiểm đều nhận ra trang đó ngay khi nhìn thấy
Chỗ giữ chỗ đó không phải là hỏng hóc. Đó chính xác là những gì định dạng quy định sẽ xảy ra khi không có bộ xử lý XFA nào hiện diện, và tính đến năm 2026 điều đó mô tả gần như mọi trình xem ngoại trừ Acrobat trên desktop. Vì vậy bước đi thực tế là chuyển đổi biểu mẫu động thành một AcroForm thuần túy trước khi nó đến bất cứ nơi nào ở hạ nguồn. HotPDF, thư viện PDF của losLab cho Delphi và C++Builder, thực hiện quá trình chuyển đổi đó trong mã lệnh, xây dựng lại biểu mẫu XML thành các trường gốc trên các trang gốc
Tại sao hai mô hình không thể cùng tồn tại
AcroForm được định nghĩa trong ISO 32000-1 §12.7. Mỗi trường là một đối tượng PDF với một chú thích widget và một luồng hình thức hiển thị, trang là nội dung PDF thực sự, và dữ liệu nằm trên đó. XFA đảo ngược điều đó: biểu mẫu là một tài liệu XML, một gói XDP được lưu trong mục /XFA của dictionary AcroForm, và các trang PDF của một biểu mẫu động chứa chỗ giữ chỗ "Vui lòng chờ" và không gì khác, vì nội dung thực sự chưa bao giờ được tuần tự hóa thành PDF. Một trình đọc xử lý một tệp theo một mô hình hoặc mô hình kia. Bỏ qua mục /XFA và bạn thấy vỏ rỗng; tôn trọng nó mà không có engine XFA và bạn thấy cảnh báo. ISO 32000-2 đã kết thúc cuộc tranh luận bằng cách loại bỏ XFA khỏi PDF 2.0, đây là lý do chính khiến "chuyển đổi trong khi chúng ta vẫn còn có thể" biến từ một trường hợp biên thành chính sách tiếp nhận thường quy
Trước khi chuyển đổi bất cứ thứ gì, hãy phân loại nó, vì không phải mọi tệp XFA đều hiển thị chỗ giữ chỗ đó. Các biểu mẫu XFA tĩnh phát hành các trang PDF đã kết xuất sẵn cạnh XML, nên chúng hiển thị ở mọi nơi và chỉ hành xử sai khi được điền vào. Các biểu mẫu động chỉ phát hành chỗ giữ chỗ đơn thuần và không dùng được cho đến khi được chuyển đổi. Điều cần tin tưởng là chính tài liệu, không bao giờ là phần mở rộng tệp hay người gửi. Một tệp hiển thị nội dung thực trong một trình xem không phải của Adobe nhưng vẫn mang một mục /XFA là tĩnh hoặc lai; một tệp hiển thị trang cảnh báo là động. Hãy ghi lại mỗi tệp tiếp nhận rơi vào nhóm nào. Hai loại này hỏng theo những cách khác nhau sau này, và một ticket về một biểu mẫu lưu trữ trống được đóng trong vài giây khi nhật ký tiếp nhận đã ghi "XFA động, đã chuyển đổi, 47 trường đã ánh xạ, 2 cảnh báo"
Chuyển đổi một tài liệu XFA đã tải thành các trường gốc
Việc chuyển đổi chạy trên một tài liệu đã có sẵn trong bộ nhớ. FlattenLoadedXFA phân tích cú pháp mẫu XFA và các gói dữ liệu của nó, bố trí biểu mẫu, và xây dựng lại nó thành các trường AcroForm trên các trang PDF thực:
var
Pdf: THotPDF;
MappedCount, I: Integer;
Warnings: TStrings;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('dynamic_xfa.pdf');
MappedCount := Pdf.FlattenLoadedXFA(True); // True = các trường vẫn có thể chỉnh sửa
Warnings := Pdf.XFAFlattenWarnings;
for I := 0 to Warnings.Count - 1 do
Log('XFA flatten warning: ' + Warnings[I]); // các phần tử chưa được ánh xạ
Pdf.SaveLoadedDocument('native_acroform.pdf');
Log(Format('Mapped %d fields', [MappedCount]));
finally
Pdf.Free;
end;
end;
Giá trị trả về và danh sách cảnh báo là đầu ra, không phải nhiễu gỡ lỗi, nên hãy giữ cả hai. Việc chuyển đổi vốn dĩ làm mất thông tin theo bản chất của nó: kịch bản XFA, các trường được tính toán, và hành vi subform động không có đối tác AcroForm nào, và XFAFlattenWarnings nêu tên mọi phần tử mẫu không được ánh xạ. Lưu trữ tệp đã chuyển đổi mà không có danh sách cảnh báo của nó và một ngày nào đó bạn sẽ nhìn chằm chằm vào một hộp tổng trống trong một bản sao đã lưu trữ mà không có bất kỳ bản ghi nào về lý do tại sao. Cờ Editable kiểm soát liệu các trường mới có vẫn điền được hay không. Truyền True khi mọi người tiếp tục làm việc với biểu mẫu sau đó, và khóa các giá trị lại khi mục tiêu là một bản ghi đông cứng
Kiểm tra một lần chuyển đổi một phần bằng trực quan, một phần bằng cấu trúc, và bạn cần cả hai nửa. Nửa cấu trúc thì dễ: xác nhận số lượng trường khớp với MappedCount. Nửa trực quan mới là nửa bắt được thiệt hại thực sự. Mở biểu mẫu nguồn trong Acrobat desktop, vẫn là trình xem duy nhất chạy engine XFA, cạnh tệp đã chuyển đổi trong một trình đọc thông thường, và so sánh các giá trị và bố cục trên ít nhất một mẫu đã điền cho mỗi mẫu biểu mẫu. Một ngày mà engine XFA hiển thị dưới dạng 2026-06-11 có thể rơi vào bản sao AcroForm dưới dạng một giá trị thô, chưa định dạng, và chỉ mắt bạn mới bắt được điều đó
Khi đầu vào là một gói XDP
Không phải mọi tác vụ đều bắt đầu từ một PDF đã có dữ liệu. Đôi khi bạn nhận được gói XDP riêng lẻ, được xuất từ một công cụ thiết kế biểu mẫu hoặc được chuyển giao bởi một hệ thống đối tác. ApplyXFAAsAcroForm bỏ qua bước tải và áp dụng gói đó trực tiếp vào tài liệu hiện tại:
XDPBytes := TFile.ReadAllBytes('benefit-claim.xdp');
MappedCount := Pdf.ApplyXFAAsAcroForm(XDPBytes, True);
Cùng một nhóm lệnh gọi cũng chạy theo chiều ngược lại, cho trường hợp hiếm hơn khi bạn phải phát ra XFA thay vì tiêu thụ nó. AddXFAPacket gắn các gói được đặt tên riêng lẻ như 'xdp' hoặc 'config'. SetXFADocument cài đặt một payload luồng đơn hoàn chỉnh trong một lệnh gọi. ClearXFAPackets xóa sạch đăng ký để bạn có thể bắt đầu lại, và AddXFASignaturePacket nhúng tài liệu XAdES cho các quy trình làm việc ký trực tiếp dữ liệu biểu mẫu XML. Việc tạo ra XFA vào năm 2026 là một nhu cầu ngách, gần như luôn bị ép buộc bởi một bên tiêu thụ kế thừa duy nhất từ chối bất cứ thứ gì khác, nhưng khi một hợp đồng nêu tên nó, các lệnh gọi này giữ nó ở mức một lựa chọn cấu hình thay vì một công cụ riêng biệt
Ý nghĩa khác của "làm phẳng"
Từ "flatten" (làm phẳng) làm vấp nhiều cuộc trò chuyện, vì nó đặt tên cho một thao tác hoàn toàn khác: đốt các hình thức hiển thị trường AcroForm vào luồng nội dung trang cho đến khi không còn đối tượng tương tác nào sót lại. HotPDF hiện không có API cho việc đó, và bạn muốn biết điều này ngay bây giờ thay vì giữa chừng một dự án. Thứ thư viện cung cấp cho bạn thay vào đó là khóa ở cấp độ trường khi trường được tạo ra, được hỗ trợ bởi các quyền hạn tài liệu:
// Khóa giá trị khi tạo trường: trường văn bản chỉ đọc
Pdf.CurrentPage.AddTextField('CaseNumber', 'BC-2026-0117',
Rect(50, 700, 220, 720), 0, [ffReadOnly]);
// Phòng hờ hai lớp: hạn chế việc điền biểu mẫu trên toàn tài liệu
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.OwnerPassword := 'records-owner';
Pdf.ProtectOptions := [prPrint, prInformationCopy, prExtractContent];
// quyền điền bị giữ lại: prFillAnnotations không có trong tập hợp
Hãy rõ ràng về những gì điều đó mang lại cho bạn và những gì nó không mang lại. Một trường chỉ đọc vẫn là một đối tượng biểu mẫu. Nó xuất hiện trong bảng điều khiển trường của trình xem, giá trị của nó đọc được thông qua API biểu mẫu, và một công cụ ghi lại tệp có thể xóa cờ chỉ đọc một lần nữa. Các cờ quyền hạn nâng cao ngưỡng nhưng phụ thuộc vào việc trình xem chọn tôn trọng chúng, một giới hạn mà ISO 32000-1 nêu rõ ràng. Khi một cơ quan quản lý khăng khăng rằng một bản ghi lưu trữ không được chứa bất kỳ đối tượng biểu mẫu nào cả, câu trả lời trung thực với HotPDF ngày nay là xây dựng lại tài liệu: đọc các giá trị ra, rồi vẽ chúng như nội dung TextOut thông thường trên một trang mới, thay vì trang điểm các cờ chỉ đọc thành làm phẳng. Một điều cần nhớ trên con đường quyền hạn là CryptKeyLength phải được đặt trước BeginDoc; phần còn lại nằm trong bài viết về mã hóa AES-256 và quyền hạn của chúng tôi
XFA có ý nghĩa gì đối với sự tuân thủ lưu trữ
Cả PDF/A và PDF/X đều từ chối XFA hoàn toàn. Vì vậy một pipeline nạp vào một kho lưu trữ ISO 19005 phải chuyển đổi trước, và thứ tự này không thể thương lượng: tải, FlattenLoadedXFA, lưu, rồi mới chạy việc tạo hoặc xác thực lưu trữ trên kết quả AcroForm. Đừng coi việc chuyển đổi như một bằng chứng của sự tuân thủ. Nó chỉ sửa mô hình biểu mẫu và để nguyên phông chữ, màu sắc, và siêu dữ liệu như chúng vốn có, nên hãy xác thực đầu ra bằng veraPDF trước khi tin tưởng nó. Một khi biểu mẫu đã ở phía AcroForm, hành vi của nó có bộ điều khiển riêng. Các trình kích hoạt JavaScript, hành động submit, và script xác thực được trình bày trong bài viết về các trường và hành động AcroForm của HotPDF
Các API đăng ký, chuyển đổi, và biểu mẫu XFA được trình bày ở đây đi kèm với HotPDF Delphi Component cho Delphi và C++Builder, tài liệu của nó theo dõi bộ tính năng XFA khi nó đã phát triển qua các bản phát hành gần đây