Technikai cikk

FDF, XFDF és XFA űrlapadat-csere Delphiben

A losLab PDF Library három különböző módon mozgatja az űrlapadatokat a PDF-be és onnan ki: FDF és XFDF az AcroForm mezőértékekhez, ugyanez a két formátum a megjegyzésekhez (annotations), valamint egy teljes XFA XDP csomag közvetlenül az űrlapba írva. A belépési pontok az ExportFormDataToXFDF, ImportFormDataFromXFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF és SetXFAFromString, és mindegyiknek létezik fájl- és karakterlánc-változata is

A sok metódus oka az, hogy a PDF-űrlapadat nem egyetlen dolgot jelent. Egy kitöltött AcroForm mezőértékeket tartalmaz, hordozhat ellenőrzési megjegyzéseket is, egy régi XFA űrlap pedig egy egész XML alkalmazásleírást ágyaz be, amelynek egyikhez sincs köze. A losLab PDF Library szándékosan külön API-kon tartja ezt a három szempontot, mivel ezek összevonása legalább kettőre rossz adatmodellt kényszerítene rá. Az első tervezési döntés annak kiválasztása, hogy melyik családra van szüksége, és ez általában abban a pillanatban eldől, amikor megtudja, hogy a másik oldalon lévő fogadó rendszer valójában mit dolgoz fel

Mi a különbség az FDF, XFDF és XFA űrlapadatok között?

Az FDF és az XFDF ugyanazt az információt hordozza két különböző szintaxisban, az XFA pedig egy külön világ. Az FDF egy miniatűr PDF-szintaxisú dokumentum (ISO 32000-2 §12.7.8): << /T (név) /V (érték) >> szótárak /Fields tömbje, a karakterláncok pedig pontosan úgy vannak escape-elve, ahogy a literál karakterláncok a PDF-ben. Az XFDF ugyanazon adatok XML formája (ISO 19444), egy <fields> fa, amelyet az Acrobat és a legtöbb űrlap-háttérrendszer natívan olvas és ír. Az XFA egyik sem: ez egy XML Forms Architecture sablon és a hozzá tartozó adatok, XML Data Package (XDP) formájában tárolva, amelyre a PDF az /AcroForm/XFA útvonalról hivatkozik. Válassza az FDF-et vagy az XFDF-et, ha mezőértékeken végez műveleteket, és csak akkor nyúljon az XFA-hoz, ha olyan dokumentumot tart karban, amelyet eleve XFA-űrlapként hoztak létre

Az FDF-en és XFDF-en belül a losLab PDF Library egy második határvonalat is húz: mezőértékek kontra megjegyzések (annotations). Az űrlapadat-család (ExportFormDataToFDF, ImportFormDataFromFDF, ExportFormDataToXFDF, ImportFormDataFromXFDF) a /Fields részfát olvassa és írja, és semmi máshoz nem nyúl. Ezzel szemben a megjegyzés-család (ExportAnnotationsToFDF, ImportAnnotationsFromFDF, ExportAnnotationsToXFDF, ImportAnnotationsFromXFDF) a /Annots részfát írja és olvassa, amit az Acrobat „Megjegyzések exportálása” (Export Comments) alatt ért. A kettő soha nem fedi egymást, így a mezőértékek exportálása nem fogja összesöpörni a kósza véleményezési jegyzeteket, a megjegyzések importálása pedig nem fogja megzavarni a felhasználó által már beírt értékeket. Az, hogy egy widget mit tesz, ha rákattintanak vagy újraszámolják, egy harmadik szempont, amelyet az interaktív űrlapműveletekről és JavaScriptről szóló kísérő cikk tárgyal

Hogyan tölthető fel egy PDF űrlap FDF-ből vagy XFDF-ből Delphiben?

Töltse be a dokumentumot, hívjon meg egy importálási metódust, majd mentse el. Az ImportFormDataFromXFDF és az ImportFormDataFromFDF elemezi a bejövő űrlapadatokat, a teljes képzettségű nevük (fully qualified name) alapján megfeleltet minden bejegyzést egy AcroForm mezőnek, beállítja az értéket, és visszaadja a ténylegesen frissített mezők számát. Mindkét metódus csak azokat a mezőket frissíti, amelyek már léteznek a cél PDF-ben; egyik sem hoz létre mezőt olyan névhez, amelyet az űrlap nem definiál, ami megakadályozza, hogy egy kósza vagy rosszindulatú adatfájl csendben kibővítse az űrlapot

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;

Két részlet határozza meg, hogy a nem triviális adatok túlélik-e az utat. Az első az escape-elés: az FDF az értékeket PDF literál karakterláncként tárolja, így a zárójelet, visszaperjelet vagy nem nyomtatható bájtot tartalmazó érték az ISO 32000-2 §7.3.4.2 szabványban meghatározott oktális escape-eléssel érkezik, ja a losLab PDF Library importáláskor megfordítja ezt az escape-elést, így a zárójelek és perjelek a felhasználó által beírt literál karakterekként térnek vissza. A második a kódolás: a fájlalapú metódusok az XFDF-et és FDF-et UTF-8-ként írják és olvassák, amit az XFDF deklaráció is ígér, és amire minden nem ASCII mezőértéknek (ékezetes név, pénznemszimbólum, CJK cím) szüksége van ahhoz, hogy sérülés nélkül végbemenjen az oda-vissza út. Ha Ön építi fel az XFDF-et, deklaráljon UTF-8-at és írjon UTF-8-at, és az importálás egyet fog érteni Önnel

Hierarchikus mezők, többértékű választások és formázott szöveg

A hierarchikus mezőnevek az első hely, ahol egy naiv exportőr elakad. Az AcroForm egy beágyazott mezőt egy ponttal elválasztott teljes címmel címez meg, mint például az Applicant.FullName, de az XFDF nem helyezi ezt a pontozott karakterláncot egyetlen név attribútumba; az ISO 19444 beágyazza azt, mint <field name="Applicant"><field name="FullName">. A losLab PDF Library exportáláskor a pontozott címet beágyazott <field> elemekre bontja, importáláskor pedig visszaállítja a beágyazott elemeket a teljes címmé, így a két irány szimmetrikus marad. Exportáláskor kihagyja a nem terminális szülőmezőket is, mivel az AcroForm szülőcsomópontja csak a névszintet hordozza, és nincs saját értéke; kibocsátása egy üres <value></value> elemet eredményezne, amely nem egyezik a valódi űrlappal. A több kijelölést támogató listadobozok a második csapda: egy választómező egyszerre több kijelölt értéket is tartalmazhat, amit az XFDF ismételt <value> elemekkel fejez ki, az FDF pedig egy /V tömbbel, a losLab PDF Library pedig csak akkor bont egy mezőt több értékre, ha az valóban több kijelölésű választás, így egy normál többsoros szövegmező megtartja a soremeléseit ahelyett, hogy hamis értékekre töredezne

A formázott szöveg (rich text) a harmadik, és ezt rontják el a leggyakrabban. Egy formázott mező a jelöléseit az RV bejegyzésben tárolja XHTML részfaként, az XFDF pedig a <value-richtext> elemben hordozza. A losLab PDF Library ezt a részfát élő XML töredékként írja le ahelyett, hogy escape-elné, így a feldolgozó eszköz valódi formázott szöveget olvas a látható tag-ek sorozata helyett; importáláskor megőrzi a nyers RV részfát, és a sima <value> értéket továbbra is alkalmazza a V-re. Ha egy mező mindkettőt felkínálja, a sima érték nyer a V esetében, a formázott szöveg pedig mellette fut az RV-ben; ez az az együttműködési szabály, amely megakadályozza, hogy a formázott szöveg importálása csendben felülírjon egy olyan értéket, amelyet egy másik eszköz már beállított. Ha a formázott szöveg a dokumentum szerkezetét hivatott közvetíteni a kisegítő technológiák felé, kezelje ugyanúgy, mint a címkézett PDF-ről és a hozzáférhetőségi struktúráról szóló megjegyzésben tárgyalt olvasási sorrendet

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;

Hogyan küldhetők oda-vissza a megjegyzések FDF vagy XFDF formátumban?

A megjegyzések a megjegyzés-családon utaznak, és a támogatott részhalmaz szándékosan kicsi. Az ExportAnnotationsToXFDF és ImportAnnotationsFromXFDF, valamint FDF megfelelőik szöveges stílusú jelölést hordoznak azokkal a mezőkkel, amelyek valóban tisztán round-tripelhetők: a megjegyzés altípusa, téglalapja, 0-alapú oldalközépe, a szerző a T-ben, a tárgy a Subj-ban, a sima Contents és a szín, amely a PDF /C DeviceRGB hármasát képezi le egy XFDF #RRGGBB attribútumra és vissza. Az importálás csak az ismert elemneveket fogadja el, és kihagy minden olyan bejegyzést, amelynek oldala tartományon kívül esik, vagy amelynek téglalapja hiányzik, így egy kézzel szerkesztett vagy idegen XFDF nem tud hibás megjegyzést dobni a dokumentumba. Az, amit a részhalmaz még nem hordoz, érdemes világosan kimondani: a formázott szöveges tartalom (RC), a felugró ablakok, a quadpointok, a tintalisták, a csúcspontok és a beégetett megjelenési folyamatok jelenleg kívül esnek a hatókörön, így a kiemelési geometria és az egyedi bélyegzők megjelenése nem éli túl ezt az utat. A vizsgált adatok ellenőrzéséhez járja be az oldalmegjegyzéseket vagy a szöveges keresés és oldalelem-felsorolás témakörében leírt tágabb elemfát

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;

Teljes XFA XDP csomag írása a SetXFAFromString segítségével

Az XFA a kakukktojás, és a SetXFAFromString segítségével írhatja meg az egészet egyszerre. A metódus egy teljes XML Data Package-et vesz át, a <xdp:xdp> dokumentumot a sablon- és adatkészlet-csomagjaival együtt, és azt az /AcroForm/XFA útvonalról hivatkozott adatfolyamként tárolja. A losLab PDF Library szükség esetén létrehozza az AcroForm konténert, ha a dokumentumnak nincs ilyenje, így nem kell egy felesleges mezőt hozzáadnia csak azért, hogy az XFA-nak legyen hova kapcsolódnia, és elvet minden általa tárolt, korábban elemzett XFA állapotot, így egy későbbi olvasás a frissen írt csomagot tükrözi a régi gyorsítótár helyett. Mivel az XFA-csomag XML, és nem feltétlenül UTF-8, a könyvtár észleli a UTF-16 bájt-sorrend jelet (BOM), és elemzés előtt helyesen dekódolja a csomagot, ami fontos a UTF-16 alapértelmezett kódolást használó eszközök által előállított csomagoknál

Miután a csomag a helyére került, a GetXFAFormFieldValue és a SetXFAFormFieldValue metódusok egyedi mezőket címeznek meg a Scripting Object Model útvonalukon keresztül. A losLab PDF Library elfogadja a standard SOM gyökereket és a csupasz relatív útvonalakat is, így a form1.FullName, a $data.form1.FullName és az xfa.datasets.data.form1.FullName mind ugyanarra az adatcsomópontra mutatnak, és a sablon oldal ugyanígy elfogadja a $template és xfa.template gyökereket is. Ez a tolerancia akkor fontos, ha a SOM útvonalakat egy másik rendszer állítja elő, amely mindig a teljes képzettségű formát bocsátja ki

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;

Ahol a pontosság véget ér

Az őszinte összefoglaló az, hogy a mezőértékek teljes mértékben round-tripelhetők FDF és XFDF segítségével, beleértve a hierarchiát, a több kijelölést és a formázott szöveget; a megjegyzések meghatározott szöveges stílusú részhalmazként járnak oda-vissza, egyértelmű hiányosságokkal; az XFA pedig egy teljes csomagként írható és olvasható, mezőnkénti SOM-hozzáféréssel kiegészítve. Igazítsa a formátumot a felhasználóhoz, deklaráljon UTF-8-at minden kézzel készített dologhoz, és ne feledje, hogy az importálási metódusok csak olyan mezőket és megjegyzéseket érintenek, amelyek már illeszkednek a dokumentumhoz. Az itt leírt űrlapadat-, megjegyzés- és XFA-metódusok a Delphihez és C++Builderhez készült losLab PDF Library részét képezik, amelynek referenciája tartalmazza az összes exportálási és importálási belépési pont teljes paraméterlistáját