PDF Library for Delphi (PDFlibPas) skriver Web Capture-kommandometadata ind i et dokuments catalog via AddWebCaptureCommand og udfylder /SpiderInfo-ordbogen defineret i ISO 32000-1 §14.10. Hver kommando registrerer den URL, der blev hentet, hvor mange niveauer dybt hentningen gik, og et lille sæt flags. Den registrerer hensigten — den henter ikke noget
Den skelnen er hele grunden til, at dette API er let at misforstå. En supportingeniør giver dig en PDF samlet fra en leverandørs online-dokumentation og spørger, hvor side 40 kommer fra. Hvis producenten udfyldte /SpiderInfo, står svaret i catalog'et: en URL, en crawl-dybde, måske selve POST-body'en, der producerede siden. Hvis producenten ikke gjorde det, kan ingen mængde læsning af content stream'en fortælle dig det. At skrive den proveniens er billigt, strukturelt besværligt og næsten altid sprunget over
Hvad gemmer Catalog-/SpiderInfo-ordbogen egentlig?
/SpiderInfo er en Web Capture-informationsordbog, der hænger på dokumentets catalog, og den indeholder præcis to ting, PDF Library for Delphi bekymrer sig om: /V, en numerisk Web Capture-databaseversion, som biblioteket altid skriver som 1.0, og /C, et array af kommandoordbøger. Versionsnummeret er ikke PDF-versionen — det identificerer selve Web Capture-datamodellen, og 1.0 er den eneste værdi, ISO 32000-1 §14.10 definerer. Alt det interessante bor i /C. Hver kommandoordbog bærer /URL (adressen, der blev forespurgt), /L (hvor mange niveauer af links, der blev fulgt derfra) og /F (traversal-flags). Tre valgfrie nøgler beskriver selve forespørgslen, når den ikke var en almindelig GET: /P for POST-data, /CT for content type på de data og /H for yderligere request-headers. PDF Library for Delphi mapper alle seks på én record, TPDFlibWebCaptureCommand, hvis felter er URL, Levels, Flags, PostData, ContentType og Headers, alle AnsiString undtagen de to Integer-tællere. Tilstedeværelsen af /SpiderInfo skubber også dokumentets minimumsversion op: AddWebCaptureCommand kalder EnsureMinVersion('1.3', 'Catalog /SpiderInfo Web Capture command'), og versionsdetektionsreglerne i PDF Library for Delphi registrerer en matchende PDF 1.3-regel, så et dokument, der læses tilbage senere, rapporterer samme minimum
Hvorfor en Web Capture-kommando skal være et indirekte objekt
Den ene strukturelle regel, der snubler folk: En kommandoordbog skal registreres som et indirekte objekt, før den kommer ind i /C, fordi ISO 32000-1 §14.10 specificerer /C som et array af indirekte referencer til kommandoordbøger, ikke et array af ordbøger. Skubber du en direkte ordbog ind i det array, får du noget, der parser som gyldig PDF og intet betyder som Web Capture-record — en viewer eller et arkiveringsværktøj, der gennemgår kommandolisten, finder et inline-objekt, hvor der skulle stå en reference, og posten er simpelthen ikke en kommando. PDF Library for Delphi håndterer dette inde i AddWebCaptureCommand: Den bygger ordbogen, giver den til OnNewIndObj for at få et objektnummer og et generationsnummer, pakker parret i en indirekte reference og tilføjer referencen til arrayet. Hvis OnNewIndObj ikke producerer et positivt objektnummer, returnerer funktionen 0, og arrayet efterlades urørt. Grunden til, at spec'en insisterer på indirektion, er, at en enkelt kommando kan deles — den samme hentning kan refereres fra mere end ét sted i en Web Capture-struktur — og delte objekter i PDF er per definition indirekte
Hvordan tilføjer du en Web Capture-kommando fra Delphi?
Udfyld recoden fuldstændigt, og kald derefter AddWebCaptureCommand, som returnerer den nye kommandos 1-baserede indeks eller 0, hvis valideringen afviste den. Fuldstændighed betyder mere end normalt her. Delphi initialiserer de managed AnsiString-felter i en lokal record til tom, men Integer-felterne — Levels og Flags — får ingen sådan behandling, så en record, du glemmer at udfylde, ankommer med lige det, der lå på stakken. AddWebCaptureCommand kræver, at Levels er mindst 1, og at Flags er ikke-negativ, og en stak-skrald-værdi bliver enten afvist med det samme eller, værre, lydløst accepteret som en plausibel dybde
var
Lib: TPDFlib;
Command: TPDFlibWebCaptureCommand;
Index: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('captured-site.pdf', '') = 1 then
begin
// Tildel alle felter: Levels og Flags er almindelige Integers og
// bærer stak-skrald, hvis du springer dem over.
Command.URL := 'https://example.com/docs/index.html';
Command.Levels := 2;
Command.Flags := PDF_WEB_CAPTURE_SAME_SITE or PDF_WEB_CAPTURE_SAME_PATH;
Command.PostData := '';
Command.ContentType := '';
Command.Headers := '';
// Returnerer det nye 1-baserede kommandindeks eller 0 ved afvisning.
Index := Lib.AddWebCaptureCommand(Command);
if Index = 0 then
raise Exception.Create('Web Capture command rejected');
Lib.SaveToFile('captured-site.pdf');
end;
finally
Lib.Free;
end;
end;
Det første succesfulde kald er også det, der opretter strukturen. AddWebCaptureCommand beder den interne WebCaptureCommands(True)-helper om kommandoarrayet, og den helper opretter /SpiderInfo med sin /V-post og derefter et tomt /C-array, kun hvis de mangler. Den er bevidst konservativ om det, den finder: Hvis catalog'et allerede har en /SpiderInfo-nøgle, hvis værdi ikke er en ordbog, eller en /C-nøgle, hvis værdi ikke er et array, returnerer helperen nil i stedet for at overskrive det eksisterende objekt. En malformed nedarvet struktur får tilføjelsen til at fejle; den får ikke PDF Library for Delphi til at ødelægge, hvad den tidligere producent skrev
Flag-whitelisten: tre definerede bits og intet andet
AddWebCaptureCommand validerer Flags mod en whitelist og afviser enhver værdi med en bit sat uden for de tre konstanter, PDF Library for Delphi definerer: PDF_WEB_CAPTURE_SAME_SITE = 1 (følg kun links, der bliver på samme site), PDF_WEB_CAPTURE_SAME_PATH = 2 (følg kun links under samme sti) og PDF_WEB_CAPTURE_SUBMIT = 4 (denne forespørgsel var en form-submission og ikke en almindelig hentning). Giver du 8, 16 eller et tilfældigt -1, returnerer kaldet 0 uden at røre dokumentet
Dette er strengere, end PDF-parsere normalt er, og det er med vilje. /F er et bitfelt uden selvbeskrivende struktur, så en udefineret bit kan ikke skelnes fra en korrumperet, og en forbruger, der senere læser værdien tilbage, har ingen måde at skelne en fremtidig udvidelse fra en tastefejl. At afvise ved skrivetidspunktet holder tvetydigheden helt ude af filen. Bemærk også, at /P, /CT og /H kun skrives, når deres tilsvarende record-felter er ikke-tomme, så en almindelig GET producerer en kommandoordbog med tre nøgler — /URL, /L, /F — uden tomme streng-pladsholdere, der fylder, hvilket er det, en reader, der parser filen, forventer for en forespørgsel uden body
// En form-submission: POST-body plus dens content type.
Command.URL := 'https://example.com/search';
Command.Levels := 1;
Command.Flags := PDF_WEB_CAPTURE_SUBMIT; // 4
Command.PostData := 'q=iso32000&scope=all';
Command.ContentType := 'application/x-www-form-urlencoded';
Command.Headers := 'Accept-Language: en-US';
if Lib.AddWebCaptureCommand(Command) = 0 then
raise Exception.Create('submission command rejected');
// Same-site plus same-path er en lovlig kombination: 1 eller 2 = 3.
Command.Flags := PDF_WEB_CAPTURE_SAME_SITE or PDF_WEB_CAPTURE_SAME_PATH;
// Bit 3 er ikke defineret af spec'en, så denne når aldrig frem til filen.
Command.Flags := 8;
if Lib.AddWebCaptureCommand(Command) <> 0 then
raise Exception.Create('undefined flag bit should have been refused');
At læse kommandoer tilbage: én nøgle, to lovlige repræsentationer
GetWebCaptureCommand returnerer 1 ved succes og 0 ellers, og den skal være mere tolerant end writeren, fordi den læser filer, andre producenter skrev. To asymmetrier betyder noget. For det første accepterer readeren en kommandopost, uanset om den er en indirekte reference eller en direkte ordbog, og derefererer, når det er nødvendigt — PDF Library for Delphi skriver altid den indirekte form, spec'en kræver, men at nægte at læse en sjusket fil hjælper ingen. For det andet må /P være enten en string eller en stream, og den generaliserer godt langt ud over Web Capture. ISO 32000-1 lader gentagne gange en enkelt nøgle holde enten en string eller en stream, når værdien kan være vilkårligt stor — POST-bodies her, og samme mønster dukker op andre steder i formatet for metadata og embedded payloads. Den interne ReadString-helper i GetWebCaptureCommand tager derfor et AllowStream-flag, og kun /P-læsningen passerer True: En stream-værdi afkodes gennem sin filterkæde og returneres som PostData-feltet, mens /URL, /CT og /H forbliver string-only, fordi spec'en ikke byder dem på stream-alternativet. Skriver du din egen PDF-læsekode, er det her vanen værd at stjæle — tjek spec'en for, hvilke nøgler der er dobbelt-typiserede, i stedet for at antage en string
var
Lib: TPDFlib;
Command: TPDFlibWebCaptureCommand;
I, Total, Removed: Integer;
begin
Total := Lib.GetWebCaptureCommandCount;
// Offentlig indeksering er 1-baseret, ligesom resten af PDF Library for Delphi.
for I := 1 to Total do
if Lib.GetWebCaptureCommand(I, Command) = 1 then
Writeln(Format('%s levels=%d flags=%d post=%d bytes',
[Command.URL, Command.Levels, Command.Flags, Length(Command.PostData)]));
// Fjerner hele /SpiderInfo-ordbogen og rapporterer, hvor mange
// kommandoer der blev droppet; returnerer 0, når der ikke var noget at rydde.
Removed := Lib.ClearWebCaptureCommands;
Writeln(Format('cleared %d command(s)', [Removed]));
end;
ClearWebCaptureCommands tæller kommandoerne og fjerner derefter hele /SpiderInfo-nøglen fra catalog'et i stedet for blot at tømme /C. At efterlade et /SpiderInfo med et tomt kommandoarray ville hævde, at dokumentet har Web Capture-proveniens, og at intet blev hentet, hvilket er en anden og falsk påstand end at have ingen registreret proveniens. Det samme instinkt gælder catalog-metadata generelt — en tom skalordbog er en udtalelse, ikke en neutral rest. Hvis du reviderer, hvad et dokument allerede hævder, før du omskriver det, passer introspectionsmønsteret i at læse outline- og annotation-actions tilbage ud af en eksisterende PDF naturligt sammen med et read-then-clear-pass her
At skrive metadata er ikke at implementere Web Capture
Vær ærlig over for dig selv om omfanget: AddWebCaptureCommand gemmer en record af en tilsigtet eller fuldført hentning, og det er alt, den gør. PDF Library for Delphi udfører ikke HTTP-forespørgsler, følger ikke de links, din Levels-værdi beskriver, og respekterer ikke SAME_SITE- eller SAME_PATH-flaggene — de flags er dokumentation for, hvordan en eller anden crawler opførte sig, ikke instruktioner, biblioteket udfører. Din egen hentekode, uanset hvad den er, forbliver helt dit problem
To yderligere dele af ISO 32000-1 §14.10 er også uden for dette API. Web Capture definerer content sets — /Contents-strukturerne, der binder individuelle side-dele tilbage til det kildemateriale, de kom fra — og et name tree, der mapper digitale identifikatorer til de content sets. PDF Library for Delphi vedligeholder ingen af delene. Det, du får, er kommandolisten: det top-level-svar på "hvor blev dette dokument hentet fra, og hvor dybt gik crawlen", som for proveniens-, audit- og arkivmodtagelsesformål normalt er den del, nogen faktisk spørger om. Skal URL'erne være klikbare for læsere i stedet for blot registreret for revisorer, er det et separat job — se at bygge GoToR-, GoToE- og Launch-actions for action-siden og document- og page-lifecycle-action-triggers for udløsende adfærd ved åbning eller lukning. Catalog-/SpiderInfo-kommandometadata som beskrevet her er en del af PDF Library for Delphi, det native PDF-bibliotek til Delphi og C++Builder