PDF Library for Delphi slår sammen to AcroForm-dokumenter med en eksplisitt policy for felt som deler et navn. MergeDocumentEx tar imot kildedokumentidentifikatoren og én av tre strategier: dfsReject avviser sammenslåingen, dfsMerge beholder det delte navnet og synkroniserer verdier, og dfsAutoNumber omdøper de innkommende feltene deterministisk. Navneskanningen skjer før noen objektnumre skifter, så en avvist sammenslåing lar begge dokumentene forbli fullt brukbare
Alle som har satt sammen en PDF-søknadspakke, har støtt på dette. Tre skjemaer, hvert med et felt kalt Signature eller Date eller Total, blir slått sammen til én fil. I en AcroForm er det fullt kvalifiserte feltnavnet identiteten til feltet, så to felt med det samme navnet er ikke to felt i det hele tatt: å fylle ut det ene fyller ut det andre, og en signatur påført det ene dekker et omfang ingen hadde tenkt
Hvorfor avgjøres navnekollisjonen før sammenslåingen?
Den eldre MergeDocument setter sammen de to AcroForm-rot-feltarrayene og tilbyr ikke noe valg. Verre, når resultatet er ubrukelig, skjer oppdagelsen etter at objektnumre er omnummerert og sidetrær er sydd sammen, noe som etterlater den kallende parten med et dokument i en tilstand ingen av originalene var i
MergeDocumentEx snur rekkefølgen. Den samler inn toppnivå-feltnavnene fra begge dokumentene, sammenligner dem, og anvender strategien før noe flytter på seg. En avvisning er derfor en ren no-op: måldokumentet er urørt, kildedokumentet er urørt, og begge forblir åpne og brukbare, noe sammenslåingstesten verifiserer ved å lese en feltverdi tilbake ut av kilden etter en avvist sammenslåing
Sammenligningen bruker et ordnet, versalfølsomt navnesett, så kostnaden er proporsjonal med det kombinerte feltantallet ganger en logaritmisk faktor snarere enn med produktet av de to antallene. Versalfølsomhet er det riktige valget her fordi PDF-feltnavn er versalfølsomme; å folde dem ville slått sammen felt spesifikasjonen behandler som distinkte
De tre strategiene, og når hver er riktig
dfsReject er strategien for automatiserte pipeliner som ikke må produsere tvetydige dokumenter. Sammenslåingen returnerer null, og LastErrorCode rapporterer 705, en dedikert kode slik at duplikatnavn kan skilles fra enhver annen sammenslåingsfeil og rutes til en spesifikk løsning, som regel omdøping av felt tidligere i kjeden
dfsMerge beholder det delte navnet bevisst og synkroniserer målverdien og standardverdien inn i kildefeltet, slik at en samsvarende visningsklient behandler de flere widgetene som ett logisk navngitt felt, som er standard AcroForm-oppførsel for et felt med flere widget-annotasjoner. Det den ikke gjør, er å folde forskjellige feltordbøker inn i ett enkelt objekt. Hvert felt beholder sin egen sidetilknytning, utseende og handlinger, fordi å slå dem sammen stille ville kastet bort formatering og oppførsel som hører til det innkommende dokumentet
dfsAutoNumber omdøper innkommende duplikater ved å legge til et numerisk suffiks som starter på _2 og tar det første ledige. Resultatet er reproduserbart: det avhenger bare av navnene som er til stede, aldri av feltobjektnumre, så å slå sammen det samme dokumentparet to ganger gir de samme navnene begge gangene. Den egenskapen betyr noe når nedstrømskode, en FDF-import eller en databasekartlegging refererer til felt etter navn
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
// Begge dokumentene er fremdeles intakte - prøv på nytt med en policy
Log('duplicate field names; retrying with auto-numbering');
Lib.MergeDocumentEx(SourceDoc, dfsAutoNumber);
end;
end;
Lib.SaveToFile('application-complete.pdf');
finally
Lib.Free;
end;
end;
Legg merke til totrinnsmønsteret i den koden, som bare er mulig fordi avvisning er ikke-destruktivt. Prøv den strenge policyen først, inspiser feilen, avgjør deretter. Med en sammenslåing som feiler halvveis, måtte reserveløsningen startet på nytt ved å laste inn begge filene igjen
Hvordan det sammenslåtte skjemaet ser ut etterpå
Under dfsMerge produserer et målfelt kalt Shared som bærer «Target value», og et kildefelt med det samme navnet, to felt, begge kalt Shared, begge rapporterende målverdien, fordi målverdien og standardverdien synkroniseres inn i det innkommende feltet. Det er den tiltenkte semantikken for et delt navn: ett logisk felt, flere widgets, én verdi
Under dfsAutoNumber produserer den samme inndataen Shared og Shared_2 som separate felt med uavhengige verdier. Velg mellom de to ved å stille ett enkelt spørsmål: skal det å fylle ut den ene kontrollen fylle ut den andre? For et signatørnavn gjentatt på hver del av en pakke, ja, og dfsMerge er riktig. For en sum som betyr noe forskjellig på hvert skjema, nei, og autonummerering er riktig
// Etter en sammenslåing, ramse opp hva du faktisk fikk
for I := 1 to Lib.FormFieldCount do
Log(Format('%d: %s = %s',
[I, Lib.GetFormFieldTitle(I), Lib.GetFormFieldValue(I)]));
Praktiske merknader for å sette sammen skjemapakker
Den vellykkede sammenslåingen forbruker kildedokumentet: det fjernes fra bibliotekets dokumentliste, som er grunnen til at DocumentCount faller fra to til én. Ikke fortsett å bruke kildeidentifikatoren etterpå. Dokumentversjonen heves til den høyeste av de to, så å slå et PDF 2.0-skjema sammen med et 1.7-dokument gir en 2.0-fil
Rekkefølge betyr noe for navn. Å slå sammen A inn i B og å slå sammen B inn i A produserer forskjellige autonummererte resultater, siden dokumentet som utfører sammenslåingen, beholder sine navn uendret. Når en pakke har et kanonisk primærskjema, gjør det til målet
Signaturfelt fortjener sin egen vurdering. En signatur som ble påført før en sammenslåing, dekker bare revisjonen den signerte, så sammenslåing gjør den ugyldig i den praktiske forstand at filen har endret seg siden signering. Sett sammen først og signer det sammensatte dokumentet, fremfor å slå sammen signerte deler. Når sammenslåingen handler om sideinnhold snarere enn skjemaer, er den raskere banen beskrevet i rask PDF-sammenslåing med byte-referanseforskyvning det bedre verktøyet
Til slutt, planlegg datasiden av pakken sammen med sammenslåingen. Hvis feltverdier kommer fra et eksternt system, avgjør om det systemet adresserer felt etter navn før du velger autonummerering, fordi Shared_2 ikke vil matche en kartlegging som forventer Shared. Import- og eksportformater er dekket i FDF, XFDF og XFA skjemadatautveksling, og skripting på feltnivå-oppførsel som også kan påvirkes av omdøping, er dekket i interaktive skjemahandlinger og JavaScript
Skjemasammenslåing, datautveksling og signering kjører i det samme biblioteket for Delphi, C++Builder og Free Pascal; den komplette funksjonslisten finnes på PDF Library for Delphi-siden