A PDF Library for Delphi explicit szabályzattal egyesít két AcroForm-dokumentumot az azonos nevű mezőkre vonatkozóan. A MergeDocumentEx a forrásdokumentum-azonosítót és három stratégia egyikét várja: a dfsReject elutasítja az egyesítést, a dfsMerge megtartja a megosztott nevet és szinkronizálja az értékeket, a dfsAutoNumber pedig determinisztikusan átnevezi a beérkező mezőket. A névvizsgálat azelőtt történik, hogy bármely objektumszám elmozdulna, így egy elutasított egyesítés mindkét dokumentumot teljesen használhatóan hagyja
Bárki, aki már összeállított egy PDF-jelentkezési csomagot, belefutott ebbe. Három űrlap, mindegyikben egy Signature, Date vagy Total nevű mező, egyetlen fájlba egyesítve. Egy AcroForm-ban a teljesen minősített mezőnév a mező azonossága, így két azonos nevű mező egyáltalán nem két mező: az egyik kitöltése kitölti a másikat is, egy az egyikre alkalmazott aláírás pedig olyan hatókört fed le, amelyet senki nem szándékozott
Miért a mezőnévütközés dől el az egyesítés előtt?
A régebbi MergeDocument egyszerűen összefűzi a két AcroForm gyökér mezőtömbjét, és nem kínál választást. Ami rosszabb, amikor az eredmény használhatatlan, a felfedezés azután történik, hogy az objektumszámokat újraszámozták, és az oldalfákat összevarrták, ami a hívónak egy olyan állapotú dokumentumot hagy a kezében, amilyenben egyik eredeti sem volt
A MergeDocumentEx megfordítja a sorrendet. Összegyűjti a felső szintű mezőneveket mindkét dokumentumból, összehasonlítja őket, és a stratégiát azelőtt alkalmazza, hogy bármi elmozdulna. Egy elutasítás ezért egy tiszta no-op: a céldokumentum érintetlen, a forrásdokumentum érintetlen, mindkettő nyitva és használható marad, amit az egyesítési teszt egy elutasított egyesítés után a forrásból visszaolvasott mezőértékkel ellenőriz
Az összehasonlítás egy rendezett, kis- és nagybetűt megkülönböztető névhalmazt használ, így a költség a kombinált mezőszám és egy logaritmikus tényező szorzatával arányos, nem a két szám szorzatával. A kis- és nagybetű-érzékenység itt a helyes választás, mert a PDF-mezőnevek kis- és nagybetűérzékenyek; ha hajtogatnánk őket, az egyesítené azokat a mezőket, amelyeket a specifikáció eltérőnek kezel
A három stratégia, és mikor melyik a helyes
A dfsReject az a stratégia olyan automatizált folyamatokhoz, amelyek nem állíthatnak elő kétértelmű dokumentumokat. Az egyesítés nullát ad vissza, a LastErrorCode pedig 705-öt jelent, egy dedikált kódot, hogy a duplikált nevek megkülönböztethetők legyenek minden más egyesítési hibától, és egy konkrét orvosláshoz irányíthatók legyenek, általában a mezők előzetes átnevezéséhez
A dfsMerge szándékosan megtartja a megosztott nevet, és szinkronizálja a célértéket és az alapértelmezett értéket a forrásmezőbe, így egy megfelelőségi néző a több widgetet egyetlen logikailag elnevezett mezőként kezeli, ami szabványos AcroForm-viselkedés egy több widget-annotációval rendelkező mezőnél. Amit nem tesz meg, hogy különböző mezőszótárakat egyetlen objektumba olvasztana. Minden mező megtartja a saját oldalkapcsolatát, megjelenését és akcióit, mert az összevonásuk csendben eldobná a beérkező dokumentumhoz tartozó formázást és viselkedést
A dfsAutoNumber a beérkező duplikátumokat egy _2-nél kezdődő numerikus utótag hozzáfűzésével nevezi át, az első szabadot választva. Az eredmény reprodukálható: csak a jelen lévő nevektől függ, soha a mező objektumszámaitól, így ugyanazon dokumentumpár kétszeri egyesítése mindkétszer ugyanazokat a neveket adja. Ez a tulajdonság akkor számít, amikor egy downstream kód, egy FDF-import vagy egy adatbázis-leképezés név szerint hivatkozik mezőkre
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
// Mindkét dokumentum még mindig sértetlen - próbáld újra egy szabályzattal
Log('duplicate field names; retrying with auto-numbering');
Lib.MergeDocumentEx(SourceDoc, dfsAutoNumber);
end;
end;
Lib.SaveToFile('application-complete.pdf');
finally
Lib.Free;
end;
end;
Figyeld meg a kétlépéses mintát abban a kódban, amely csak azért lehetséges, mert az elutasítás nem romboló jellegű. Próbáld ki előbb a szigorú szabályzatot, vizsgáld meg a hibát, majd dönts. Egy félúton elbukó egyesítéssel a visszaesésnek elölről kellene kezdenie mindkét fájl újratöltésével
Hogyan néz ki az egyesített űrlap utána?
A dfsMerge alatt egy Shared nevű, „Target value” értéket hordozó célmező és egy ugyanilyen nevű forrásmező két mezőt eredményez, mindkettő Shared néven, mindkettő a célértéket jelenti, mert a célérték és az alapértelmezett érték szinkronizálva van a beérkező mezőbe. Ez a szándékolt szemantika egy megosztott névhez: egy logikai mező, több widget, egy érték
A dfsAutoNumber alatt ugyanaz a bemenet Shared-et és Shared_2-t ad, mint különálló mezőket, független értékekkel. A kettő közötti választáshoz egyetlen kérdést tegyél fel: az egyik vezérlő kitöltésének ki kell-e töltenie a másikat is? Egy aláíró nevéhez, amely a csomag minden részén ismétlődik, igen, és a dfsMerge a helyes. Egy olyan összeghez, amely minden űrlapon mást jelent, nem, és az automatikus számozás a helyes
// Egy egyesítés után soroltasd fel, mit kaptál valójában
for I := 1 to Lib.FormFieldCount do
Log(Format('%d: %s = %s',
[I, Lib.GetFormFieldTitle(I), Lib.GetFormFieldValue(I)]));
Gyakorlati megjegyzések űrlapcsomagok összeállításához
A sikeres egyesítés elfogyasztja a forrásdokumentumot: az eltávolításra kerül a könyvtár dokumentumlistájáról, ezért csökken a DocumentCount kettőről egyre. A forrásazonosítót ezután ne használd tovább. A dokumentumverzió a kettő közül a magasabbra emelkedik, így egy PDF 2.0 űrlap egy 1.7-es dokumentumba egyesítése 2.0-s fájlt ad
A sorrend számít a neveknél. Az A-nak B-be egyesítése és a B-nek A-ba egyesítése eltérő automatikusan számozott eredményeket ad, mivel az egyesítést végző dokumentum megtartja a neveit változatlanul. Ha egy csomagnak van kanonikus elsődleges űrlapja, azt tedd meg célnak
Az aláírásmezők saját megfontolást érdemelnek. Egy egyesítés előtt alkalmazott aláírás csak azt a revíziót fedi le, amelyet aláírt, így az egyesítés a gyakorlati értelemben érvényteleníti azt, hogy a fájl megváltozott az aláírás óta. Előbb állítsd össze, majd írd alá az összeállított dokumentumot, ahelyett hogy aláírt részeket egyesítenél. Amikor az egyesítés oldaltartalomról szól, nem űrlapokról, a gyors PDF-egyesítés bájt-hivatkozás-eltolással ismertetett gyorsabb útvonal a jobb eszköz
Végül a csomag adatoldalát az egyesítéssel együtt tervezd meg. Ha a mezőértékek egy külső rendszerből érkeznek, döntsd el, hogy az a rendszer név szerint címzi-e a mezőket, mielőtt automatikus számozást választanál, mert a Shared_2 nem fog egyezni egy olyan leképezéssel, amely Shared-et vár. Az import- és exportformátumokat az FDF-, XFDF- és XFA-űrlapadat-csere ismerteti, az átnevezés által szintén érintett mezőszintű szkriptviselkedést pedig az interaktív űrlapakciók és JavaScript ismerteti
Az űrlap-egyesítés, az adatcsere és az aláírás ugyanabban a könyvtárban fut Delphihez, C++Builderhez és Free Pascalhoz; a teljes funkciólista a PDF Library for Delphi oldalán található