PDF Library for Delphi (PDFlibPas), Web Capture komut meta verilerini bir belgenin kataloğuna AddWebCaptureCommand üzerinden yazar ve ISO 32000-1 §14.10'da tanımlanan /SpiderInfo sözlüğünü doldurur. Her komut, getirilen URL'yi, getirinin kaç düzey derine indiğini ve küçük bir bayrak kümesini kaydeder. Niyeti kaydeder — hiçbir şey getirmez
Bu ayrım, bu API'nin yanlış okunmasının bu kadar kolay olmasının tüm nedenidir. Bir destek mühendisi size bir satıcının çevrimiçi dokümantasyonundan derlenmiş bir PDF uzatır ve sayfa 40'ın nereden geldiğini sorar. Üretici /SpiderInfo'yu doldurduysa yanıt katalogda duruyordur: bir URL, bir tarama derinliği, belki sayfayı üreten POST gövdesi. Üretici doldurmadıysa, içerik akışını okumak size hiçbir şey söylemez. Bu kaynağı yazmak ucuzdur, yapısal olarak titizdir ve neredeyse her zaman atlanır
Katalog /SpiderInfo sözlüğü gerçekte neyi kaydeder?
/SpiderInfo, belge kataloğuna asılı bir Web Capture bilgi sözlüğüdür ve PDF Library for Delphi'nin önemsediği tam olarak iki şeyi tutar: kütüphanenin her zaman 1.0 olarak yazdığı sayısal Web Capture veritabanı sürümü /V ve bir komut sözlükleri dizisi olan /C. Sürüm numarası PDF sürümü değildir — Web Capture veri modelinin kendisini tanımlar ve 1.0, ISO 32000-1 §14.10'un tanımladığı tek değerdir. İlginç olan her şey /C içinde yaşar. Her komut sözlüğü /URL (istenen adres), /L (ondan kaç düzey bağlantı izlendiği) ve /F (dolaşım bayrakları) taşır. Düz bir GET olmadığında isteğin kendisini üç isteğe bağlı anahtar tanımlar: POST verisi için /P, bu verinin içerik türü için /CT ve ek istek başlıkları için /H. PDF Library for Delphi altısını da tek bir kayda, alanları URL, Levels, Flags, PostData, ContentType ve Headers olan ve iki Integer sayacı dışında hepsi AnsiString olan TPDFlibWebCaptureCommand kaydına eşler. /SpiderInfo'nun varlığı ayrıca belgenin minimum sürümünü yükseltir: AddWebCaptureCommand, EnsureMinVersion('1.3', 'Catalog /SpiderInfo Web Capture command') çağırır ve PDF Library for Delphi'deki sürüm algılama kuralları eşleşen bir PDF 1.3 kuralı kaydeder; böylece daha sonra geri okunan bir belge aynı tabanı rapor eder
Bir Web Capture komutu neden dolaylı bir nesne olmak zorunda?
İnsanları çelmeleyen tek yapısal kural: bir komut sözlüğü, /C'ye girmeden önce dolaylı bir nesne olarak kaydedilmelidir, çünkü ISO 32000-1 §14.10 /C'yi sözlükler dizisi değil, komut sözlüklerine dolaylı başvurular dizisi olarak tanımlar. Diziye doğrudan bir sözlük iterseniz, geçerli PDF olarak ayrışan ama Web Capture kaydı olarak hiçbir şey ifade etmeyen bir şey elde edersiniz — komut listesini dolaşan bir görüntüleyici veya arşiv aracı, başvurunun olması gereken yerde satır içi bir nesne bulur ve girdi basitçe bir komut değildir. PDF Library for Delphi bunu AddWebCaptureCommand içinde halleder: sözlüğü kurar, nesne numarası ve üretim numarası almak için OnNewIndObj'ye verir, bu çifti dolaylı bir başvuruya sarar ve başvuruyu diziye ekler. OnNewIndObj pozitif bir nesne numarası üretemezse fonksiyon 0 döndürür ve diziye dokunulmaz. Belirtimin dolaylılıkta ısrar etmesinin nedeni, tek bir komutun paylaşılabilmesidir — aynı getirme, bir Web Capture yapısında birden fazla yerden başvurulabilir — ve PDF'de paylaşılan nesneler tanım gereği dolaylı olanlardır
Delphi'den bir Web Capture komutu nasıl eklersiniz?
Kaydı tamamen doldurun, ardından yeni komutun 1 tabanlı dizinini veya doğrulama reddederse 0 döndüren AddWebCaptureCommand'ı çağırın. Burada eksiksizlik her zamankinden daha önemlidir. Delphi, yerel bir kaydın yönetilen AnsiString alanlarını boş olarak başlatır, ama Integer alanları — Levels ve Flags — böyle bir muamele görmez; doldurmayı unuttuğunuz bir kayıt, yığında ne varsa onu taşıyarak gelir. AddWebCaptureCommand, Levels'in en az 1 ve Flags'in negatif olmamasını gerektirir ve bir yığın çöpü değeri ya doğrudan reddedilir ya da daha kötüsü, makul görünen bir derinlik olarak sessizce kabul edilir
var
Lib: TPDFlib;
Command: TPDFlibWebCaptureCommand;
Index: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('captured-site.pdf', '') = 1 then
begin
// Her alanı ata: Levels ve Flags düz Integer'dır ve
// onları atlarsanız yığın çöpü taşırlar.
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 := '';
// Yeni 1 tabanlı komut dizinini döndürür, reddedilirse 0.
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;
Yapıyı oluşturan da ilk başarılı çağrıdır. AddWebCaptureCommand, komut dizisi için dahili WebCaptureCommands(True) yardımcısını ister ve bu yardımcı, /SpiderInfo'yu /V girdisiyle ve ardından boş bir /C dizisini yalnızca eksiklerse oluşturur. Bulduğu şey konusunda kasıtlı olarak muhafazakârdır: katalogda değeri sözlük olmayan bir /SpiderInfo anahtarı veya değeri dizi olmayan bir /C anahtarı zaten varsa, yardımcı mevcut nesnenin üzerine yazmak yerine nil döndürür. Bozuk bir kalıtsal yapı eklemeyi başarısız kılar; PDF Library for Delphi'nin önceki üreticinin yazdıklarını yok etmesine neden olmaz
Bayrak beyaz listesi: üç tanımlı bit ve başka hiçbir şey
AddWebCaptureCommand, Flags'i bir beyaz listeye karşı doğrular ve PDF Library for Delphi'nin tanımladığı üç sabitin dışında bir bit set eden herhangi bir değeri reddeder: PDF_WEB_CAPTURE_SAME_SITE = 1 (yalnızca aynı sitede kalan bağlantıları izle), PDF_WEB_CAPTURE_SAME_PATH = 2 (yalnızca aynı yol altındaki bağlantıları izle) ve PDF_WEB_CAPTURE_SUBMIT = 4 (bu istek düz bir getirme değil bir form gönderimiydi). 8, 16 veya kazara bir -1 geçerseniz çağrı, belgeye dokunmadan 0 döndürür
Bu, PDF ayrıştırıcılarının genelde olduğundan daha katıdır ve bilerek. /F, kendini tanımlayan bir yapısı olmayan bir bit alanıdır; bu yüzden tanımsız bir bit, bozuk bir bitten ayırt edilemez ve değeri daha sonra geri okuyan bir tüketici, gelecekteki bir uzantıyı bir yazım hatasından ayırt edemez. Yazma anında reddetmek belirsizliği tamamen dosyanın dışında tutar. Ayrıca not edin: /P, /CT ve /H yalnızca karşılık gelen kayıt alanları boş olmadığında yazılır; böylece sıradan bir GET, gövdeli olmayan bir istek için dosyayı ayrıştıran bir okuyucunun beklediği gibi, boş dize yer tutucularıyla kirlenmemiş üç anahtarlı bir komut sözlüğü — /URL, /L, /F — üretir
// Bir form gönderimi: POST gövdesi artı içerik türü.
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');
// Aynı site artı aynı yol yasal bir kombinasyondur: 1 veya 2 = 3.
Command.Flags := PDF_WEB_CAPTURE_SAME_SITE or PDF_WEB_CAPTURE_SAME_PATH;
// Bit 3 belirtimde tanımlı değildir, bu yüzden bu dosyaya asla ulaşmaz.
Command.Flags := 8;
if Lib.AddWebCaptureCommand(Command) <> 0 then
raise Exception.Create('undefined flag bit should have been refused');
Komutları geri okumak: bir anahtar, iki yasal temsil
GetWebCaptureCommand başarıda 1, aksi hâlde 0 döndürür ve yazıcıdan daha hoşgörülü olmak zorundadır, çünkü başka üreticilerin yazdığı dosyaları okur. İki asimetri önemlidir. Birincisi, okuyucu bir komut girdisini dolaylı bir başvuru veya doğrudan bir sözlük olarak kabul eder, gerektiğinde referansı çözer — PDF Library for Delphi her zaman belirtimin gerektirdiği dolaylı biçimi yazar, ama özensiz bir dosyayı okumayı reddetmek kimseye fayda sağlamaz. İkincisi, /P'nin bir dize veya bir akış olmasına izin verilir ve bu, Web Capture'ın çok ötesine genelleşir. ISO 32000-1, değer keyfi olarak büyük olabildiğinde tek bir anahtarın bir dize veya bir akış tutmasına defalarca izin verir — burada POST gövdeleri ve aynı kalıp biçimin başka yerlerinde meta veriler ve gömülü yükler için görünür. Bu yüzden GetWebCaptureCommand içindeki dahili ReadString yardımcısı bir AllowStream bayrağı alır ve yalnızca /P okuması True geçer: bir akış değeri filtre zincirinden çözülür ve PostData alanı olarak döndürülür; /URL, /CT ve /H ise yalnızca dize kalır, çünkü belirtim onlara akış seçeneğini sunmaz. Kendi PDF okuma kodunuzu yazıyorsanız, çalmaya değer alışkanlık budur — bir dize varsaymak yerine hangi anahtarların çift türlü olduğunu belirtimden kontrol edin
var
Lib: TPDFlib;
Command: TPDFlibWebCaptureCommand;
I, Total, Removed: Integer;
begin
Total := Lib.GetWebCaptureCommandCount;
// Genel dizinleme, PDF Library for Delphi'nin geri kalanıyla eşleşen 1 tabanlıdır.
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)]));
// Tüm /SpiderInfo sözlüğünü kaldırır ve kaç komutun atıldığını bildirir;
// temizlenecek bir şey yoksa 0 döndürür.
Removed := Lib.ClearWebCaptureCommands;
Writeln(Format('cleared %d command(s)', [Removed]));
end;
ClearWebCaptureCommands komutları sayar, ardından katalogdan yalnızca /C'yi boşaltmak yerine tüm /SpiderInfo anahtarını temizler. Boş bir komut dizisiyle geride bir /SpiderInfo bırakmak, belgenin Web Capture kaynağına sahip olduğunu ve hiçbir şeyin getirilmediğini iddia etmek olurdu ki bu, kaynak kaydı olmamasından farklı ve yanlış bir iddiadır. Aynı içgüdü genel olarak katalog meta verileri için de geçerlidir — boş bir kabuk sözlüğü bir ifadedir, nötr bir kalıntı değil. Bir belgeyi yeniden yazmadan önce ne iddia ettiğini denetliyorsanız, mevcut bir PDF'den anahat ve açıklama eylemlerini geri okuma deseni burada bir oku-sonra-temizle geçişiyle doğal biçimde eşleşir
Meta veri yazmak Web Capture uygulamak değildir
Kapsam konusunda kendinize karşı dürüst olun: AddWebCaptureCommand, amaçlanan veya tamamlanmış bir getirmenin kaydını kaydeder ve yaptığı tek şey budur. PDF Library for Delphi HTTP istekleri yapmaz, Levels değerinizin tarif ettiği bağlantıları izlemez ve SAME_SITE veya SAME_PATH bayraklarını yerine getirmez — bu bayraklar, bir tarayıcının nasıl davrandığının dokümantasyonudur, kütüphanenin yürüttüğü talimatlar değil. Kendi getirme kodunuz, ne olursa olsun, tamamen sizin sorununuzdur
ISO 32000-1 §14.10'un iki parçası daha bu API'nin dışındadır. Web Capture, içerik kümelerini — tek tek sayfa parçalarını geldikleri kaynak materyale bağlayan /Contents yapılarını — ve bu içerik kümelerine dijital tanımlayıcıları eşleyen bir ad ağacını tanımlar. PDF Library for Delphi ikisini de tutmaz. Elde ettiğiniz şey komut listesidir: "bu belge nereden getirildi ve tarama ne kadar derine indi" sorusunun üst düzey yanıtı; kaynak, denetim ve arşiv alımı amaçları için genelde herkesin gerçekten sorduğu kısım budur. URL'lerin denetçiler için yalnızca kaydedilmek yerine okuyucular için tıklanabilir olması gerekiyorsa bu ayrı bir iştir — eylem tarafı için GoToR, GoToE ve Launch eylemleri kurma ve açılışta veya kapanışta tetikleme davranışı için belge ve sayfa yaşam döngüsü eylem tetikleyicileri bölümlerine bakın. Burada anlatıldığı gibi katalog /SpiderInfo komut meta verileri, Delphi ve C++Builder için yerel PDF kütüphanesi olan PDF Library for Delphi'nin bir parçasıdır