שני טפסים יכולים להכיל את אותם שדות ולהתנהג באופן שונה לחלוטין. AcroForm שומר את שדותיו כאובייקטי PDF רגילים המונחים מעל תוכן דף אמיתי, כך שכל קורא תואם מציג אותם. טופס XFA דינמי כמעט ואינו שומר דבר כ-PDF: השדות, הפריסה ואפילו גאומטריית הדף חיים בחבילת XML, והדפים הגלויים נוצרים בעת פתיחה על ידי מנוע פריסה שרק Adobe אי פעם שלחה באופן נרחב. הזן את הקובץ הזה לצופה ווב, לעורך ארכיון או למחלץ טקסט ולא תקבל את הטופס. תקבל דף אפור בודד עם הכיתוב "Please wait... If this message is not eventually replaced by the proper contents of the document, your PDF viewer may not be able to display this type of document." מי שעסק בניירות ממשלתיים או ביטוחיים מכיר את הדף הזה ממבט ראשון
ה-placeholder אינו שחיתות. הוא בדיוק מה שהפורמט מציין שצריך לקרות כשאין מעבד XFA, ואחרי 2026 זה מתאר כמעט כל צופה מחוץ ל-Acrobat השולחני. לכן הצעד המעשי הוא להמיר את הטופס הדינמי ל-AcroForm רגיל לפני שהוא מגיע לכל דבר במורד הזרם. HotPDF, ספריית ה-PDF של losLab עבור Delphi ו-C++Builder, מבצעת המרה זו בקוד ובונה מחדש את טופס ה-XML כשדות מקוריים על דפים מקוריים
מדוע שני המודלים אינם יכולים לדור בכפיפה אחת
AcroForm מוגדר ב-ISO 32000-1 §12.7. כל שדה הוא אובייקט PDF עם הערת widget וזרם מראה, הדף הוא תוכן PDF אמיתי והנתונים מונחים מעליו. XFA הופך זאת: הטופס הוא מסמך XML, חבילת XDP המאוחסנת בערך /XFA של מילון AcroForm, ודפי ה-PDF של טופס דינמי מכילים את ה-placeholder "Please wait" ותו לא, כי התוכן האמיתי מעולם לא סוּדרר כ-PDF. קורא מעבד קובץ לפי אחד המודלים. התעלם מרשומת ה-/XFA ותראה את הקליפה הריקה; כבד אותה ללא מנוע XFA ותראה את האזהרה. ISO 32000-2 סיים את הוויכוח בכך שהחסיר את XFA מ-PDF 2.0, שהוא הסיבה העיקרית שבגללה "להמיר כל עוד ניתן" עבר ממקרה קצה למדיניות קליטה שגרתית
לפני שממירים כל דבר, יש לסווג אותו, כי לא כל קובץ XFA מציג את ה-placeholder. טפסי XFA סטטיים מגיעים עם דפי PDF מעובדים מראש לצד ה-XML, כך שהם מוצגים בכל מקום ומתנהגים לא כשורה רק כשממלאים. טפסים דינמיים מגיעים עם ה-placeholder בלבד ואינם שמישים עד שממירים. מה שיש לסמוך עליו הוא המסמך, לא הסיומת ולא השולח. קובץ המציג תוכן אמיתי בצופה שאינו Adobe אך עדיין נושא רשומת /XFA הוא סטטי או היברידי; קובץ המציג את דף האזהרה הוא דינמי. תעד לאיזה קטגוריה נכנס כל קובץ קליטה. שני הסוגים נכשלים בדרכים שונות מאוחר יותר, וכרטיס על טופס ארכיון ריק נסגר תוך שניות כשיומן הקליטה כבר רשום "XFA דינמי, הומר, 47 שדות מומפו, 2 אזהרות"
המרת מסמך XFA טעון לשדות מקוריים
ההמרה רצה מול מסמך שכבר נמצא בזיכרון. FlattenLoadedXFA מנתח את תבנית ה-XFA וחבילות הנתונים שלה, מסדר את הטופס ובונה אותו מחדש כשדות AcroForm על דפי PDF אמיתיים:
var
Pdf: THotPDF;
MappedCount, I: Integer;
Warnings: TStrings;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('dynamic_xfa.pdf');
MappedCount := Pdf.FlattenLoadedXFA(True); // True = fields stay editable
Warnings := Pdf.XFAFlattenWarnings;
for I := 0 to Warnings.Count - 1 do
Log('XFA flatten warning: ' + Warnings[I]); // unmapped elements
Pdf.SaveLoadedDocument('native_acroform.pdf');
Log(Format('Mapped %d fields', [MappedCount]));
finally
Pdf.Free;
end;
end;
ערך ההחזרה ורשימת האזהרות הם פלט, לא רעש לצורכי ניפוי שגיאות, לכן שמור את שניהם. המרה מאבדת מידע מטבעה: סקריפטינג XFA, שדות מחושבים והתנהגות subform דינמי אין להם מקבילה ב-AcroForm, ו-XFAFlattenWarnings מציין כל אלמנט תבנית שלא מומפה. ארכוב קובץ ממורה ללא רשימת האזהרות שלו ויום אחד תביט בתיבת סיכום ריקה בעותק ארכיון ללא תיעוד מדוע. הדגל Editable שולט בשאלה האם השדות החדשים נשארים ניתנים למילוי. העבר True כשאנשים ממשיכים לעבוד עם הטופס לאחר מכן, ונעל את הערכים כשהמטרה היא רשומה קפואה
בדיקת המרה היא חלקית ויזואלית וחלקית מבנית, ואתה צריך את שני החצאים. החצי המבני קל: ודא שספירת השדות תואמת את MappedCount. החצי הויזואלי הוא זה שתופס נזק אמיתי. פתח את הטופס המקורי ב-Acrobat השולחני, עדיין הצופה היחיד שמריץ את מנוע XFA, לצד הקובץ הממורה בקורא רגיל, והשווה ערכים ופריסה על לפחות דוגמה ממולאת אחת לכל תבנית. תאריך שמנוע ה-XFA הציג כ-2026-06-11 יכול להגיע לעותק AcroForm כערך גולמי ובלתי מעוצב, ורק עיניך יתפסו זאת
כשהקלט הוא חבילת XDP
לא כל עבודה מתחילה מ-PDF ממולא. לפעמים מקבלים את חבילת XDP בפני עצמה, מיוצאת מכלי עיצוב טפסים או מועברת על ידי מערכת שותפה. ApplyXFAAsAcroForm מדלג על שלב הטעינה ומחיל את החבילה ישירות על המסמך הנוכחי:
XDPBytes := TFile.ReadAllBytes('benefit-claim.xdp');
MappedCount := Pdf.ApplyXFAAsAcroForm(XDPBytes, True);
אותה קבוצת קריאות רצה גם בכיוון ההפוך, עבור המקרה הנדיר שבו יש לפלוט XFA ולא לצרוך אותו. AddXFAPacket מצרף חבילות בעלות שם בודדות כמו 'xdp' או 'config'. SetXFADocument מתקין עומס עצמאי שלם בזרם אחד בקריאה אחת. ClearXFAPackets מנקה את הרישום כך שאפשר להתחיל מחדש, ו-AddXFASignaturePacket מטמין חומר XAdES עבור זרימות עבודה שחותמות על נתוני טופס ה-XML ישירות. ייצור XFA ב-2026 הוא צורך נישה, כמעט תמיד נאכף על ידי צרכן מדור קודם שמסרב לכל דבר אחר, אך כשחוזה מגדיר זאת, קריאות אלה מורידות את הדבר לבחירת קונפיגורציה במקום כלי נפרד
המשמעות האחרת של "שיטוח"
המילה "שיטוח" מבלבלת הרבה שיחות, כי היא מגדירה פעולה שנייה לחלוטין: שריפת מראות שדות AcroForm לתוך זרם תוכן הדף עד שלא נותרים אובייקטים אינטראקטיביים. ל-HotPDF אין ממשק API לכך כיום, ועדיף לדעת זאת עכשיו ולא באמצע פרויקט. מה שהספרייה נותנת במקום זאת הוא נעילה ברמת השדה כשהשדה נוצר, המגובה בהרשאות מסמך:
// Lock the value at field creation: read-only text field
Pdf.CurrentPage.AddTextField('CaseNumber', 'BC-2026-0117',
Rect(50, 700, 220, 720), 0, [ffReadOnly]);
// Belt and suspenders: restrict form filling document-wide
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.OwnerPassword := 'records-owner';
Pdf.ProtectOptions := [prPrint, prInformationCopy, prExtractContent];
// fill permission withheld: prFillAnnotations is absent from the set
היה ברור לגבי מה זה נותן לך ומה לא. שדה לקריאה בלבד הוא עדיין אובייקט טופס. הוא מופיע בלוח השדות של הצופה, ערכו קריא דרך ממשק ה-API של הטופס, וכלי שכותב מחדש את הקובץ יכול לנקות שוב את הדגל לקריאה בלבד. דגלי הרשאה מגבירים את הסף אך תלויים בצופה שיבחר לכבד אותם, מגבלה שאיזו 32000-1 מציינת במפורש. כשגוף רגולציה מתעקש שרשומה ארכיבית לא תכיל שדות טופס כלל, התשובה הכנה עם HotPDF כיום היא לבנות מחדש את המסמך: קרא את הערכים החוצה, ואז צייר אותם כתוכן TextOut רגיל על דף חדש, במקום להסוות דגלים לקריאה בלבד כשיטוח. דבר אחד לזכור בנתיב ההרשאות הוא ש-CryptKeyLength צריך להיות מוגדר לפני BeginDoc; השאר נמצא במאמר ההצפנה וההרשאות AES-256 שלנו
מה XFA אומר עבור תאימות ארכיון
PDF/A ו-PDF/X שניהם דוחים XFA על הסף. לכן צינור המזין ארכיון ISO 19005 חייב להמיר תחילה, והסדר אינו ניתן למשא ומתן: טען, FlattenLoadedXFA, שמור, ואז הרץ יצירת ארכיון או אימות על תוצאת AcroForm. אל תתייחס להמרה כהוכחת תאימות. היא מתקנת את מודל הטופס ומשאירה גופנים, צבע ומטאדאטה בדיוק כפי שהיו, לכן אמת את הפלט עם veraPDF לפני שתסמוך עליו. ברגע שהטופס נמצא בצד AcroForm, התנהגותו מקבלת מערכת שליטות משלה. טריגרים של JavaScript, פעולות שליחה וסקריפטים לאימות מכוסים במאמר שדות ופעולות AcroForm של HotPDF
ה-API של רישום XFA, המרה וטפסים המוצג כאן מגיע עם HotPDF Component עבור Delphi ו-C++Builder, שהתיעוד שלו עוקב אחר מאפייני XFA ככל שהם גדלו בגרסאות האחרונות