مقاله فنی

ادغام فرم‌های PDF در دلفی: قواعد فیلد تکراری

PDF Library for Delphi دو سند AcroForm را با یک خط‌مشی صریح برای فیلدهایی که یک نام مشترک دارند ادغام می‌کند. MergeDocumentEx شناسه سند منبع و یکی از سه استراتژی را می‌گیرد: dfsReject ادغام را رد می‌کند، dfsMerge نام مشترک را نگه می‌دارد و مقادیر را همگام می‌کند، و dfsAutoNumber فیلدهای ورودی را به‌طور قطعی تغییرنام می‌دهد. اسکن نام پیش از هر جابه‌جایی شماره شیء رخ می‌دهد، بنابراین یک ادغام ردشده هر دو سند را کاملاً قابل‌استفاده باقی می‌گذارد

هرکسی که یک بسته درخواست PDF مونتاژ کرده باشد به این برخورده. سه فرم، هرکدام با یک فیلد به نام Signature یا Date یا Total، در یک فایل ادغام می‌شوند. در یک AcroForm، نام کاملاً واجدشرایط فیلد، هویت آن فیلد است، بنابراین دو فیلد با نام یکسان اصلاً دو فیلد نیستند: پرکردن یکی، دیگری را نیز پر می‌کند، و یک امضای اعمال‌شده روی یکی، دامنه‌ای را می‌پوشاند که هیچ‌کس قصدش را نداشت

چرا برخورد نام پیش از ادغام تصمیم گرفته می‌شود؟

MergeDocument قدیمی‌تر دو آرایه فیلد ریشه AcroForm را به‌هم می‌چسباند و هیچ انتخابی ارائه نمی‌دهد. بدتر از آن، وقتی نتیجه غیرقابل‌استفاده است، کشف آن پس از شماره‌گذاری مجدد اشیا و به‌هم‌دوخته‌شدن درخت‌های صفحه رخ می‌دهد، که فراخوان را با سندی در وضعیتی رها می‌کند که هیچ‌یک از اصل‌ها در آن نبودند

MergeDocumentEx ترتیب را وارونه می‌کند. نام‌های فیلد سطح‌بالای هر دو سند را جمع می‌کند، آن‌ها را مقایسه می‌کند، و پیش از حرکت هر چیزی استراتژی را اعمال می‌کند. بنابراین یک رد، یک عملیات بدون‌اثر تمیز است: سند هدف دست‌نخورده است، سند منبع دست‌نخورده است، و هر دو باز و قابل‌استفاده باقی می‌مانند، که آزمون ادغام آن را با خواندن یک مقدار فیلد از سند منبع پس از یک ادغام ردشده تأیید می‌کند

مقایسه از یک مجموعه نام مرتب و حساس به حروف کوچک/بزرگ استفاده می‌کند، بنابراین هزینه متناسب با تعداد فیلد ترکیبی ضرب در یک ضریب لگاریتمی است نه در حاصل‌ضرب دو تعداد. حساسیت به حروف کوچک/بزرگ در اینجا انتخاب درست است زیرا نام‌های فیلد PDF حساس به حروف کوچک/بزرگ هستند؛ تاخوردن آن‌ها فیلدهایی را که مشخصات متمایز در نظر می‌گیرد ادغام می‌کرد

سه استراتژی، و هرکدام چه زمانی درست است؟

dfsReject استراتژی برای خط‌لوله‌های خودکاری است که نباید اسناد مبهم تولید کنند. ادغام صفر برمی‌گرداند و LastErrorCode کد ۷۰۵ را گزارش می‌دهد، یک کد اختصاصی تا نام‌های تکراری بتوانند از هر شکست ادغام دیگری تمیز داده شوند و به یک راه‌حل خاص مسیریابی شوند، معمولاً تغییرنام فیلدها در بالادست

dfsMerge نام مشترک را به‌عمد نگه می‌دارد و مقدار هدف و مقدار پیش‌فرض را در فیلد منبع همگام می‌کند، بنابراین یک نمایشگر منطبق چندین ابزارک را به‌عنوان یک فیلد از نظر منطقی نام‌گذاری‌شده در نظر می‌گیرد، که همان رفتار استاندارد AcroForm برای یک فیلد با چندین حاشیه‌نویسی ابزارک است. آنچه این استراتژی انجام نمی‌دهد، تاکردن دیکشنری‌های فیلد متفاوت در یک شیء واحد است. هر فیلد پیوند صفحه، ظاهر و کنش‌های مخصوص به خود را نگه می‌دارد، زیرا فروریختن آن‌ها به‌طور خاموش قالب‌بندی و رفتاری را که متعلق به سند ورودی است دور می‌ریخت

dfsAutoNumber موارد تکراری ورودی را با افزودن یک پسوند عددی که از _2 شروع می‌شود و اولین مورد آزاد را می‌گیرد، تغییرنام می‌دهد. نتیجه بازتولیدپذیر است: فقط به نام‌های موجود بستگی دارد، هرگز به شماره‌های شیء فیلد، بنابراین ادغام همان جفت اسناد دوبار همان نام‌ها را هر دو بار می‌دهد. آن ویژگی وقتی اهمیت دارد که کد پایین‌دستی، یک واردات FDF یا یک نگاشت پایگاه‌داده به فیلدها بر اساس نام ارجاع دهد

uses
  PDFlibrary;

var
  Lib: TPDFlib;
  TargetDoc, SourceDoc: Integer;
begin
  Lib := TPDFlib.Create;
  try
    TargetDoc := Lib.SelectedDocument;
    Lib.LoadFromFile('application-part1.pdf', '');

    SourceDoc := Lib.NewDocument;
    Lib.LoadFromFile('application-part2.pdf', '');

    Lib.SelectDocument(TargetDoc);
    if Lib.MergeDocumentEx(SourceDoc, dfsReject) = 0 then
    begin
      if Lib.LastErrorCode = 705 then
      begin
        // هر دو سند همچنان دست‌نخورده‌اند - دوباره با یک خط‌مشی امتحان کن
        Log('duplicate field names; retrying with auto-numbering');
        Lib.MergeDocumentEx(SourceDoc, dfsAutoNumber);
      end;
    end;

    Lib.SaveToFile('application-complete.pdf');
  finally
    Lib.Free;
  end;
end;

به الگوی دومرحله‌ای در آن کد توجه کنید، که فقط به این دلیل ممکن است که رد کردن غیرمخرب است. ابتدا خط‌مشی سخت‌گیرانه را امتحان کنید، خطا را بازرسی کنید، سپس تصمیم بگیرید. با یک ادغام که در میانه راه شکست می‌خورد، بازگشتی مجبور بود با بارگذاری دوباره هر دو فایل از نو شروع کند

فرم ادغام‌شده پس از آن چه شکلی دارد؟

تحت dfsMerge، یک فیلد هدف به نام Shared که «Target value» را حمل می‌کند و یک فیلد منبع با همان نام، دو فیلد تولید می‌کنند، هر دو به نام Shared، هر دو مقدار هدف را گزارش می‌دهند، زیرا مقدار هدف و مقدار پیش‌فرض در فیلد ورودی همگام شده‌اند. این همان معناشناسی مقصود برای یک نام مشترک است: یک فیلد منطقی، چندین ابزارک، یک مقدار

تحت dfsAutoNumber، همان ورودی Shared و Shared_2 را به‌عنوان فیلدهای جداگانه با مقادیر مستقل تولید می‌کند. با پرسیدن یک پرسش واحد بین این دو انتخاب کنید: آیا پرکردن یک کنترل باید دیگری را نیز پر کند؟ برای نام یک امضاکننده که در هر بخش از یک بسته تکرار شده، بله، و dfsMerge درست است. برای یک جمع کل که در هر فرم چیز متفاوتی معنا می‌دهد، نه، و شماره‌گذاری خودکار درست است

// پس از یک ادغام، آنچه واقعاً گرفته‌اید را شمارش کنید
for I := 1 to Lib.FormFieldCount do
  Log(Format('%d: %s = %s',
    [I, Lib.GetFormFieldTitle(I), Lib.GetFormFieldValue(I)]));

نکات عملی برای مونتاژ بسته‌های فرم

یک ادغام موفق، سند منبع را مصرف می‌کند: از فهرست اسناد کتابخانه حذف می‌شود، که به همین دلیل DocumentCount از دو به یک می‌افتد. پس از آن دیگر از شناسه منبع استفاده نکنید. نسخه سند به بالاترین یکی از آن دو ارتقا می‌یابد، بنابراین ادغام یک فرم PDF 2.0 در یک سند 1.7 یک فایل 2.0 می‌دهد

ترتیب برای نام‌ها اهمیت دارد. ادغام A در B و ادغام B در A نتایج شماره‌گذاری خودکار متفاوتی تولید می‌کنند، زیرا سندی که ادغام را انجام می‌دهد نام‌های خود را بدون تغییر نگه می‌دارد. وقتی یک بسته یک فرم اصلی متعارف دارد، همان را هدف قرار دهید

فیلدهای امضا سزاوار ملاحظه مخصوص به خود هستند. امضایی که پیش از یک ادغام اعمال شده فقط بازبینی‌ای را می‌پوشاند که امضا کرده، بنابراین ادغام آن را به این معنای عملی نامعتبر می‌کند که فایل از زمان امضاشدن تغییر کرده. ابتدا مونتاژ کنید و سند مونتاژشده را امضا کنید، به‌جای ادغام بخش‌های امضاشده. وقتی ادغام درباره محتوای صفحه است نه فرم‌ها، مسیر سریع‌تر که در ادغام سریع PDF با جابه‌جایی ارجاع بایتی شرح داده شده ابزار بهتری است

در آخر، سمت داده بسته را همراه با ادغام برنامه‌ریزی کنید. اگر مقادیر فیلد از یک سیستم خارجی می‌رسند، پیش از انتخاب شماره‌گذاری خودکار تصمیم بگیرید آیا آن سیستم فیلدها را بر اساس نام خطاب می‌کند، زیرا Shared_2 با نگاشتی که Shared را انتظار دارد مطابقت نخواهد داشت. قالب‌های وارد و صادرکردن در تبادل داده فرم FDF، XFDF و XFA پوشش داده شده، و رفتار اسکریپت‌نویسی سطح‌فیلد که می‌تواند از تغییرنام نیز تأثیر بپذیرد در کنش‌های فرم تعاملی و جاوااسکریپت پوشش داده شده

ادغام فرم، تبادل داده و امضا در یک کتابخانه واحد برای دلفی، C++Builder و Free Pascal اجرا می‌شوند؛ فهرست کامل ویژگی‌ها در صفحه PDF Library for Delphi قرار دارد