PDF Library for Delphi scala dwa dokumenty AcroForm z jawną zasadą dla pól współdzielących nazwę. MergeDocumentEx przyjmuje identyfikator dokumentu źródłowego i jedną z trzech strategii: dfsReject odmawia scalenia, dfsMerge zachowuje współdzieloną nazwę i synchronizuje wartości, a dfsAutoNumber deterministycznie zmienia nazwy przychodzących pól. Skanowanie nazw odbywa się przed jakimkolwiek przesunięciem numerów obiektów, więc odrzucone scalenie pozostawia oba dokumenty w pełni użyteczne
Każdy, kto składał pakiet wniosku PDF, na to natrafił. Trzy formularze, każdy z polem o nazwie Signature, Date albo Total, są scalane w jeden plik. W AcroForm w pełni kwalifikowana nazwa pola to tożsamość pola, więc dwa pola o tej samej nazwie to wcale nie dwa pola: wypełnienie jednego wypełnia drugie, a podpis zastosowany do jednego obejmuje zakres, którego nikt nie zamierzał
Dlaczego kolizja nazw jest rozstrzygana przed scaleniem?
Starsze MergeDocument łączy dwie tablice pól głównych AcroForm i nie daje żadnego wyboru. Co gorsza, gdy wynik jest bezużyteczny, odkrycie tego następuje po przenumerowaniu obiektów i zszyciu drzew stron, co zostawia wywołującego z dokumentem w stanie, w jakim nie był żaden z oryginałów
MergeDocumentEx odwraca tę kolejność. Zbiera nazwy pól najwyższego poziomu z obu dokumentów, porównuje je i stosuje strategię, zanim cokolwiek się przesunie. Odrzucenie jest więc czystym brakiem działania: dokument docelowy pozostaje nietknięty, dokument źródłowy pozostaje nietknięty, a oba pozostają otwarte i użyteczne, co test scalania weryfikuje, odczytując z powrotem wartość pola ze źródła po odrzuconym scaleniu
Porównanie wykorzystuje uporządkowany, rozróżniający wielkość liter zbiór nazw, więc koszt jest proporcjonalny do łącznej liczby pól razy czynnik logarytmiczny, a nie do iloczynu obu liczb. Rozróżnianie wielkości liter jest tutaj właściwym wyborem, ponieważ nazwy pól PDF rozróżniają wielkość liter; zwinięcie ich scaliłoby pola, które specyfikacja traktuje jako odrębne
Trzy strategie i kiedy każda jest właściwa
dfsReject to strategia dla zautomatyzowanych potoków, które nie mogą produkować niejednoznacznych dokumentów. Scalenie zwraca zero, a LastErrorCode zgłasza 705, dedykowany kod, dzięki czemu zduplikowane nazwy można odróżnić od każdej innej awarii scalania i skierować do konkretnego środka zaradczego, zwykle zmiany nazw pól wcześniej w potoku
dfsMerge celowo zachowuje współdzieloną nazwę i synchronizuje wartość docelową oraz wartość domyślną do pola źródłowego, więc zgodna przeglądarka traktuje kilka widżetów jako jedno logicznie nazwane pole, co jest standardowym zachowaniem AcroForm dla pola z wieloma adnotacjami widżetu. Czego nie robi, to zwijanie różnych słowników pól w jeden obiekt. Każde pole zachowuje własne powiązanie ze stroną, wygląd i akcje, ponieważ ich zwinięcie po cichu odrzuciłoby formatowanie i zachowanie należące do przychodzącego dokumentu
dfsAutoNumber zmienia nazwy przychodzących duplikatów, dołączając liczbowy sufiks zaczynający się od _2 i biorąc pierwszy wolny. Wynik jest odtwarzalny: zależy tylko od obecnych nazw, nigdy od numerów obiektów pól, więc scalenie tej samej pary dokumentów dwukrotnie daje te same nazwy za każdym razem. Ta właściwość ma znaczenie, gdy kod niżej w potoku, import FDF albo mapowanie bazy danych odwołuje się do pól po nazwie
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
// Oba dokumenty są wciąż nienaruszone - spróbuj ponownie z zasadą
Log('duplicate field names; retrying with auto-numbering');
Lib.MergeDocumentEx(SourceDoc, dfsAutoNumber);
end;
end;
Lib.SaveToFile('application-complete.pdf');
finally
Lib.Free;
end;
end;
Zwróć uwagę na dwuetapowy wzorzec w tym kodzie, możliwy wyłącznie dlatego, że odrzucenie jest niedestrukcyjne. Wypróbuj najpierw ścisłą zasadę, sprawdź błąd, a potem zdecyduj. Przy scaleniu, które zawodzi w połowie, awaryjne rozwiązanie musiałoby zaczynać od nowa przez ponowne wczytanie obu plików
Jak wygląda scalony formularz potem
Pod dfsMerge pole docelowe o nazwie Shared niosące „Target value” oraz pole źródłowe o tej samej nazwie dają dwa pola, oba nazwane Shared, oba zgłaszające wartość docelową, ponieważ wartość docelowa i wartość domyślna są synchronizowane do przychodzącego pola. To zamierzona semantyka dla współdzielonej nazwy: jedno pole logiczne, kilka widżetów, jedna wartość
Pod dfsAutoNumber to samo wejście daje Shared i Shared_2 jako osobne pola z niezależnymi wartościami. Wybieraj między nimi, zadając jedno pytanie: czy wypełnienie jednej kontrolki powinno wypełnić drugą? Dla nazwiska podpisującego powtórzonego na każdej części pakietu — tak, i dfsMerge jest właściwe. Dla sumy, która oznacza co innego na każdym formularzu — nie, i automatyczne numerowanie jest właściwe
// Po scaleniu wylicz, co faktycznie otrzymałeś
for I := 1 to Lib.FormFieldCount do
Log(Format('%d: %s = %s',
[I, Lib.GetFormFieldTitle(I), Lib.GetFormFieldValue(I)]));
Praktyczne uwagi przy składaniu pakietów formularzy
Udane scalenie konsumuje dokument źródłowy: jest on usuwany z listy dokumentów biblioteki, dlatego DocumentCount spada z dwóch do jednego. Nie kontynuuj używania identyfikatora źródłowego potem. Wersja dokumentu jest podnoszona do wyższej z dwóch, więc scalenie formularza PDF 2.0 z dokumentem 1.7 daje plik w wersji 2.0
Kolejność ma znaczenie dla nazw. Scalenie A do B i scalenie B do A dają różne wyniki automatycznego numerowania, ponieważ dokument wykonujący scalanie zachowuje swoje nazwy niezmienione. Gdy pakiet ma kanoniczny formularz główny, uczyń go celem
Pola podpisu zasługują na osobne rozważenie. Podpis zastosowany przed scaleniem obejmuje tylko rewizję, którą podpisał, więc scalenie unieważnia go w praktycznym sensie, że plik zmienił się od chwili podpisania. Złóż najpierw, a podpisz złożony dokument, zamiast scalać podpisane części. Gdy scalenie dotyczy treści stron, a nie formularzy, szybsza ścieżka opisana w szybkim scalaniu PDF z przesuwaniem odwołań bajtowych jest lepszym narzędziem
Na koniec zaplanuj stronę danych pakietu razem ze scaleniem. Jeśli wartości pól przychodzą z systemu zewnętrznego, zdecyduj, czy ten system adresuje pola po nazwie, zanim wybierzesz automatyczne numerowanie, ponieważ Shared_2 nie dopasuje się do mapowania oczekującego Shared. Formaty importu i eksportu są opisane w wymianie danych formularzy FDF, XFDF i XFA, a zachowanie skryptów na poziomie pola, na które również może wpłynąć zmiana nazwy, jest opisane w interaktywnych akcjach formularzy i JavaScript
Scalanie formularzy, wymiana danych i podpisywanie działają w tej samej bibliotece dla Delphi, C++Builder i Free Pascal; pełna lista funkcji znajduje się na stronie PDF Library for Delphi