Teknisk artikkel

FDF, XFDF og XFA-skjemadatautveksling i Delphi

losLab PDF Library overfører skjemadata inn og ut av en PDF på tre forskjellige måter: FDF og XFDF for AcroForm-feltverdier, de samme to formatene for merknadskommentarer (annotation comments), og en hel XFA XDP-pakke skrevet direkte inn i skjemaet. ExportFormDataToXFDF, ImportFormDataFromXFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF og SetXFAFromString er inngangspunktene, og hver enkelt av dem har en filvariant og en strengvariant

Grunnen til at det finnes så mange metoder er at PDF-skjemadata ikke er én enkelt ting. Et utfylt AcroForm har feltverdier, det kan også inneholde evalueringskommentarer, og et eldre XFA-skjema bygger inn en hel XML-applikasjonsbeskrivelse som ikke har noe med noen av delene å gjøre. losLab PDF Library holder bevisst disse tre oppgavene på separate API-er, fordi å slå dem sammen ville tvinge feil datamodell på minst to av dem. Å bestemme hvilken familie du trenger er det første designvalget, og det er vanligvis avgjort i det øyeblikket du vet hva det mottakende systemet på den andre siden faktisk bruker

Hva er forskjellen mellom FDF, XFDF og XFA-skjemadata?

FDF og XFDF bærer den samme informasjonen i to forskjellige syntakser, og XFA er en egen verden. FDF er et miniatyrdokument i PDF-syntaks (ISO 32000-2 §12.7.8): en /Fields-tabell med << /T (name) /V (value) >>-ordbøker, med strenger som er maskert akkurat slik litterale strenger maskeres inni en PDF. XFDF is XML-formen av de samme dataene (ISO 19444), et <fields>-tre som Acrobat og de fleste skjemabakstykker leser og skriver nativt. XFA er ingen av delene: det er en XML Forms Architecture-mal pluss tilhørende data, lagret som en XML-datapakke (XDP) som PDF-en refererer til fra /AcroForm/XFA. Velg FDF eller XFDF når du samhandler om feltverdier, og bruk XFA kun når du vedlikeholder et dokument som opprinnelig ble opprettet som et XFA-skjema

Innenfor FDF og XFDF trekker losLab PDF Library en linje til: feltverdier kontra merknadskommentarer. Skjemadata-familien (ExportFormDataToFDF, ImportFormDataFromFDF, ExportFormDataToXFDF, ImportFormDataFromXFDF) leser og skriver /Fields-undertreet og rører ingenting annet. Merknads-familien (ExportAnnotationsToFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF, ImportAnnotationsFromXFDF) leser og skriver i stedet /Annots-undertreet, som er det Acrobat mener med Eksporter kommentarer. De to overlapper aldri, så eksport av feltverdier vil ikke samle opp løse evalueringsnotater, og import av kommentarer vil ikke forstyrre verdiene en bruker allerede har tastet inn. Hva en widget gjør når den klikkes eller beregnes på nytt, er en helt annen sak, som dekkes i den tilhørende artikkelen om interaktive skjemahandlinger og JavaScript

Hvordan fyller du ut et PDF-skjema fra FDF eller XFDF i Delphi?

Last inn dokumentet, kall én importmetode, og lagre. ImportFormDataFromXFDF og ImportFormDataFromFDF analyserer hver de innkommende skjemadataene, samsvarer hver oppføring med et AcroForm-felt ved dets fullt kvalifiserte navn, setter verdien, og returnerer antallet felt som faktisk ble oppdatert. Begge metodene oppdaterer kun felt som allerede eksisterer i mål-PDF-en; ingen av dem oppretter et felt for et navn som skjemaet ikke definerer, noe som forhindrer at en løs eller fiendtlig datafil i det stille utvider skjemaet ditt

var
  Lib: TPDFlib;
  FieldsSet: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('application-blank.pdf', '');
    // XFDF produced by a case-management system, already UTF-8 on disk
    FieldsSet := Lib.ImportFormDataFromXFDF('applicant-1042.xfdf');
    if FieldsSet > 0 then
      Lib.SaveToFile('application-filled.pdf');
  finally
    Lib.Free;
  end;
end;

To detaljer avgjør om komplekse data overlever reisen. Det første er maskering (escaping): FDF lagrer verdier som litterale PDF-strenger, so en verdi som inneholder en parentes, en omvendt skråstrek eller en ikke-skrivbar byte ankommer pakket inn i den oktale maskeringen definert i ISO 32000-2 §7.3.4.2, og losLab PDF Library snur den maskeringen ved import slik at parentesene og skråstrekene kommer tilbake som de bokstavelige tegnene brukeren skrev. Det andre er koding (encoding): de filbaserte metodene skriver og leser XFDF og FDF som UTF-8, som er det XFDF-deklarasjonen lover og hva enhver ikke-ASCII feltverdi (et navn med aksenter, et valutasymbol, en CJK-adresse) trenger for å overføres frem og tilbake uten korrupsjon. Hvis du bygger XFDF-en selv, deklarer UTF-8 og skriv UTF-8, og da vil importen samsvare med dine data

Hierarkiske felt, valg med flere verdier og rik tekst

Hierarkiske feltnavn er det første stedet en naiv eksporter feiler. AcroForm adresserer et nestet felt med en punktumdelt full tittel som Applicant.FullName, men XFDF plasserer ikke den punktumdelte strengen i et enkelt navn-attributt; ISO 19444 nester det, som <field name="Applicant"><field name="FullName">. losLab PDF Library deler den punktumdelte tittelen inn i nestede <field>-elementer ved eksport, og setter sammen de nestede elementene tilbake til den fulle tittelen ved import, slik at de to retningene forblir symmetriske. Ved eksport hopper den også over ikke-terminale foreldrefelt, fordi en foreldrenode i et AcroForm kun bærer navngivingsnivået og ikke har noen egen verdi; å sende den ut ville produsert en tom <value></value> som ikke samsvarer med det virkelige skjemaet. Liste-bokser med flervalg (multi-select) er den andre fellen: et valgfelt kan inneholde flere valgte verdier samtidig, noe XFDF uttrykker som gjentatte <value>-elementer og FDF uttrykker som en /V-tabell, og losLab PDF Library deler kun et felt inn i flere verdier når det virkelig er et valg med flervalg, slik at et vanlig flerlinjers tekstfelt beholder linjeskiftene sine i stedet for å splittes opp i ugyldige verdier

Rik tekst er det tredje, og det folk oftest tar feil av. Et felt med formatering lagrer oppmerkingen sin i RV-oppføringen som et XHTML-undertre, og XFDF bærer det i <value-richtext>. losLab PDF Library skriver dette undertreet som et levende XML-fragment i stedet for å maskere det, slik at et etterfølgende verktøy leser ekte rik tekst i stedet for en streng med synlige tagger; ved import bevarer den det rå RV-undertreet og bruker fortsatt den vanlige <value>V. Der et felt tilbyr begge deler, vinner den enkle verdien for V, og den rike teksten følger med i RV, noe som er samhandlingsregelen som hindrer en rik tekst-import fra å i det stille overskrive en verdi et annet verktøy allerede har satt. Når den rike teksten eksisterer for å formidle dokumentstruktur til hjelpeteknologi, behandle den på samme måte som du ville behandlet leserekkefølgen som er diskutert i artikkelen om tagget PDF og tilgjengelighetsstruktur

var
  Lib: TPDFlib;
const
  XFDF =
    '<?xml version="1.0" encoding="UTF-8"?>' +
    '<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">' +
    '<fields>' +
    '  <field name="Applicant">' +
    '    <field name="FullName"><value>Alice Example</value></field>' +
    '  </field>' +
    '  <field name="Skills">' +
    '    <value>Delphi</value><value>PDF</value>' +
    '  </field>' +
    '  <field name="Notes">' +
    '    <value>See attachment</value>' +
    '    <value-richtext><body><p>See <b>attachment</b></p></body></value-richtext>' +
    '  </field>' +
    '</fields></xfdf>';
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('intake.pdf', '');
    // Applicant.FullName reassembles; Skills fills the /V + /I arrays;
    // Notes gets V from <value> and RV from <value-richtext>
    Lib.ImportFormDataFromXFDFString(XFDF);
    Lib.SaveToFile('intake-filled.pdf');
  finally
    Lib.Free;
  end;
end;

Hvordan overfører du merknadskommentarer frem og tilbake som FDF eller XFDF?

Kommentarer overføres med merknads-familien, og den støttede delmengden er bevisst liten. ExportAnnotationsToXFDF og ImportAnnotationsFromXFDF, sammen med sine FDF-motparter, bærer tekstbasert oppmerking med de feltene som faktisk overføres rent: merknadens undertype, dens rektangel, dens 0-baserte sideindeks, forfatteren i T, emnet i Subj, det enkle innholdet i Contents, og fargen, som kartlegger PDF-ens /C DeviceRGB-trippel til og fra et XFDF #RRGGBB-attributt. Import godtar kun kjente elementnavn og hopper over alle oppføringer der siden er utenfor området eller rektangelet mangler, slik at en manuelt redigert eller fremmed XFDF ikke kan plassere en feilformet merknad i dokumentet. What the subset does not yet carry is worth stating plainly: rich-text contents (RC), popups, quadpoints, ink lists, vertices and baked appearance streams are out of scope for now, so highlight geometry and custom stamp appearances will not survive this path. To confirm what actually landed, walk the page annotations or the wider element tree covered in tekstsøk og opplisting av sideelementer

var
  Src, Dest: TPDFlib;
  Xfdf: WideString;
begin
  Src := TPDFlib.Create;
  Dest := TPDFlib.Create;
  try
    Src.LoadFromFile('reviewed.pdf', '');
    Xfdf := Src.ExportAnnotationsToXFDFString;   // <annots> subset only

    Dest.LoadFromFile('clean-copy.pdf', '');     // pages must line up by index
    Dest.ImportAnnotationsFromXFDFString(Xfdf);
    Dest.SaveToFile('clean-copy-commented.pdf');
  finally
    Dest.Free;
    Src.Free;
  end;
end;

Skrive en komplett XFA XDP-pakke med SetXFAFromString

XFA er avviket, og SetXFAFromString er hvordan du skriver hele tingen på én gang. Metoden tar en komplett XML-datapakke, <xdp:xdp>-dokumentet med mal- og datasettpakkene sine, og lagrer det som strømmen referert til fra /AcroForm/XFA. losLab PDF Library oppretter AcroForm-beholderen ved behov når dokumentet ikke har noen, slik at du slipper å legge til et midlertidig felt bare for å gi XFA-en et sted å henge, og det forkaster enhver analysert XFA-tilstand det holdt på, slik at en heller lesing reflekterer pakken du nett opp skrev i stedet for en foreldet hurtigbuffer. Fordi en XFA-pakke er XML og ikke nødvendigvis UTF-8, oppdager biblioteket et UTF-16 byte-rekkefølge-merke (BOM) og dekoder pakken riktig før analysering, noe som er viktig for pakker produsert av verktøy som bruker UTF-16 som standard

Når pakken er på plass, adresserer GetXFAFormFieldValue og SetXFAFormFieldValue individuelle felt gjennom deres Scripting Object Model-bane. losLab PDF Library godtar standard SOM-røtter samt enkle relative baner, slik at form1.FullName, $data.form1.FullName og xfa.datasets.data.form1.FullName alle refererer til samme datanode, og malsiden godtar $template og xfa.template på samme måte. Denne toleransen er viktig når SOM-banene genereres av et annet system som alltid sender ut den fullt kvalifiserte formen

var
  Lib: TPDFlib;
const
  Xdp =
    '<?xml version="1.0" encoding="UTF-8"?>' +
    '<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">' +
    '  <template xmlns="http://www.xfa.org/schema/xfa-template/3.3/">' +
    '    <subform name="form1">' +
    '      <field name="FullName"><ui><textEdit/></ui></field>' +
    '    </subform>' +
    '  </template>' +
    '  <xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">' +
    '    <xfa:data><form1><FullName>Alice Example</FullName></form1></xfa:data>' +
    '  </xfa:datasets>' +
    '</xdp:xdp>';
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetXFAFromString(Xdp, 0);      // creates the AcroForm container if none exists
    // read back through the data DOM with an SOM path
    if Lib.GetXFAFormFieldValue('form1.FullName') = 'Alice Example' then
      Lib.SetXFAFormFieldValue('form1.FullName', 'Bob Example');
    Lib.SaveToFile('xfa-packet.pdf');
  finally
    Lib.Free;
  end;
end;

Den ærlige oppsummeringen er at feltverdier overføres fullt ut frem og tilbake gjennom FDF og XFDF, inkludert hierarki, flervalg og rik tekst; merknadskommentarer overføres som en definert delmengde av tekstoppmerking med klare mangler; og XFA skrives og leses som en hel pakke med SOM-tilgang per felt på toppen. Tilpass formatet til mottakeren, deklarer UTF-8 for alt du bygger for hånd, og husk at importmetodene kun berører felt og merknader som allerede passer til dokumentet. Skjemadata-, merknads- og XFA-metodene som beskrives her er en del av losLab PDF Library for Delphi og C++Builder, der referansen inneholder den fullstendige parameterlisten for hvert eksport- og importinngangspunkt