losLab PDF Kütüphanesi, XFA 3.3 SOM yol ifadeleri aracılığıyla dinamik XFA formlarındaki yinelenen veri düğümlerini okur ve yazar: GetXFAFormFieldValue ve SetXFAFormFieldValue; $data, $record ve !data köklerini, [*] oluşum joker kartlarını, alt eleman ve çocuk joker kartı seçicilerini, parent özelliğini, #dataGroup/#dataValue sınıf seçicilerini ve basit FormCalc tarzı koşul ifadelerini (predicates) kabul eder; böylece bir Delphi programı, devlet vergi formundaki her fatura satırını tek bir çağrıyla güncelleyebilir. Bu makale adresleme referansıdır; tüm veri kümelerini dosyalar arasında taşımak için, FDF, XFDF ve XFA form veri değişimi hakkındaki eşlik eden makaleye bakın
Sorun, bir formun düz (flat) olmayı bıraktığı anda ortaya çıkar. Dinamik bir XFA formu olarak oluşturulan bir KDV beyannamesi veya gümrük beyannamesi, Total_Price_1'den Total_Price_12'ye kadar adlandırılmış on iki alana sahip değildir; şablon DOM'unda bir kez beyan edilen ve verilerin gerektirdiği kadar somutlaştırılan tek bir Detail alt formuna sahiptir. Değerler, veri kümesi paketi içindeki ikinci bir ağaç olan Data DOM'da yaşar; burada her bir satır öğesi <Receipt> altındaki yinelenen bir <Detail> öğesidir. Düz alan adları "üçüncü satırdaki fiyatı" veya "200'ün üzerindeki her satırı" adresleyemez; Adobe XFA 3.3 spesifikasyonunun Scripting Object Model bölümünün SOM ifadelerine verdiği görev tam olarak budur ve losLab PDF Kütüphanesi XFA alan-değer API'lerinin konuştuğu sözdizimidir
Delphi'den XFA veri düğümlerini nasıl adreslersiniz?
Her veri kümesi yolu bir kökten başlar ve losLab PDF Kütüphanesi standart yazımları birbirinin yerine kabul eder: $data, xfa.datasets.data'nın XFA 3.3 kısa biçimidir; !data, xfa.datasets köklü kısa biçimdir ve kayıt işlemeyi kullanmayan paketlerde $record, veri düğümünün altındaki ilk öğe olan dış veri kaydına çözümlenir. SetXFAFormFieldAccess gibi şablon tarafı API'leri de $template ve xfa.template'i aynı şekilde kabul eder. Segmentler nokta ile ayrılmış veya eğik çizgi (slash) ile ayrılmış olabilir ($data.Receipt.Tax veya $data/Receipt/Tax); bu önemlidir çünkü GetXFAFormFieldNames alanları değer ve şablon API'lerine doğrudan geri beslenen eğik çizgiyle ayrılmış yollar olarak numaralandırır. Oluşum dizinleri spesifikasyona göre sıfır tabanlıdır, bu nedenle Detail[0] ilk satırdır. İki kaçış (escaping) kuralı, olağandışı adların adreslenebilir kalmasını sağlar: Noktayla ayrılmış bir yolda \. tam anlamıyla bir noktayı (Line\.Item) belirtirken, eğik çizgiyle ayrılmış yollar noktalara sıradan karakterler olarak davranır. Kendi XML ad alanı önekini taşıyan iş verileri yerel ada göre eşleştirilir, bu nedenle <m:Receipt> yine de Receipt'e yanıt verir
var
Lib: TPDFlib;
Tax: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('vat-return.pdf', '');
// Aynı veri düğümü için eşdeğer adresler
Tax := Lib.GetXFAFormFieldValue('Receipt.Tax');
Tax := Lib.GetXFAFormFieldValue('$data.Receipt.Tax');
Tax := Lib.GetXFAFormFieldValue('xfa.datasets.data.Receipt.Tax');
Tax := Lib.GetXFAFormFieldValue('$record.Tax');
// Sıfır tabanlı oluşum dizinine sahip eğik çizgi formu
Lib.SetXFAFormFieldValue('$record/Detail[0]/Total_Price', '251.00');
Lib.SaveToFile('vat-return-updated.pdf');
finally
Lib.Free;
end;
end;
Bir XFA formundaki yinelenen satırları programlı olarak nasıl doldurursunuz?
[*] oluşum joker kartı toplu iş aracıdır. Sayısal bir dizin tek bir kardeşi seçerken, [*] aynı ada sahip tüm kardeşleri seçer; bu nedenle $data.Receipt.Detail[*].Total_Price aynı anda her satır öğesindeki fiyat alanını adresler. Okuma işleminde, GetXFAFormFieldValue eşleşen tüm düğümlerin değerlerini | ayırıcısıyla birleştirilmiş olarak döndürür; yazma işleminde, SetXFAFormFieldValue eşleşen her düğümü aynı değerle günceller ve başarı durumunda 1 döndürür. Hiçbir şeyle eşleşmeyen bir yol, boş bir dize olarak geri okunur; bu, yazmadan önce bir dalın var olup olmadığını incelemenin ucuz yoludur
var
Lib: TPDFlib;
Prices: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('invoice.pdf', '');
// Tüm Detail satırları bir kerede: '250.00|60.00'
Prices := Lib.GetXFAFormFieldValue('$data.Receipt.Detail[*].Total_Price');
// Tek bir çağrıda her yinelenen satırda bir sütunu sıfırlayın
Lib.SetXFAFormFieldValue('$data.Receipt.Detail[*].Surcharge', '0.00');
Lib.SaveToFile('invoice-updated.pdf');
finally
Lib.Free;
end;
end;
Alt eleman (descendant), çocuk joker kartı (child-wildcard) ve üst eleman (parent) seçiciler
Üç yapısal seçici, alan adını bildiğiniz ancak tam derinliğini bilmediğiniz durumları kapsar. Alt eleman (descendant) seçici .. mevcut düğümün altındaki herhangi bir derinlikte eşleşir: $data..Total_Price veri kökünün altındaki herhangi bir yerdeki ilk Total_Price'ı bulur ve bir alt eleman yolu üzerinden yazma işlemi bu ilk eşleşen düğümü günceller. Sınıra dikkat edin: Alt eleman eşleşmesinden sonraki bir oluşum dizini kardeş dallar arasında adım atmaz, bu nedenle $data..Total_Price[0] ilk Detail satırının içinde çözümleniyorsa, $data..Total_Price[1] bir sonraki satıra atlamak yerine boş döner; hepsini istediğinizde Detail[*] kullanın. Çocuk joker kartı (child wildcard) .* her doğrudan çocuğu eşleştirir ve kalan segmentlerin filtrelemesine izin verir: $data.Receipt.*.Total_Price, doğrudan Receipt üzerinde oturan aynı isimli bir özet alanını seçmeden, Receipt'in her bir çocuk dalındaki Total_Price'a ulaşır. Son olarak, parent özelliği bir seviye yukarı tırmanır; XFA 3.3 bunu kasıtlı olarak ..'dan ayırır: $data.Receipt.Detail[1].parent.Tax ikinci satır öğesinde başlar, Receipt'e yükselir ve onun kardeş Tax değerine ulaşır
Sınıf seçiciler ve koşul ifadeleri: #dataGroup, #dataValue, .[ifade]
#class sözdizimi, XML etiketleri komut dosyası adları olarak hecelenmesi zor karakterler içerdiğinde pratik yol olan, veri DOM düğümlerini ad yerine nesne sınıfına göre adresler. losLab PDF Kütüphanesi; element çocukları olan elementleri #dataGroup ile ve element çocukları olmayan yaprak (leaf) elementleri #dataValue ile eşleştirir ve her ikisi de sayısal veya [*] oluşumlarıyla birleşir: $data.Receipt.#dataGroup[0].#dataValue[0], Receipt altındaki ilk grubun içindeki ilk değeri seçer. Koşul ifadesi (predicate) seçici .[ifade] aynı isimli kardeşleri içeriğe göre filtreler. Desteklenen koşul ifadeleri, bir çocuk değerinin >, < ve <= gibi ilişkisel operatörlerle bir sabite karşı basit karşılaştırmalarıdır; bir koşul ifadesi birkaç satırla eşleştiğinde, okumalar | ile birleştirilmiş olarak geri döner ve yazmalar her eşleşmeyi günceller
// Total_Price değeri 200'ü aşan her satırı işaretle
Lib.SetXFAFormFieldValue(
'$data.Receipt.Detail.[Total_Price > 200].Review_Flag', '1');
// Düşük değerli tüm satırların açıklamaları, birden fazla eşleştiğinde '|' ile birleştirilir
Desc := Lib.GetXFAFormFieldValue(
'$data.Receipt.Detail.[Total_Price <= 200].Description');
// Etiket adları betik yazımına direndiğinde sınıf tabanlı adresleme
Total := Lib.GetXFAFormFieldValue(
'$data.Receipt.#dataGroup[0].#dataValue[0]');
Hangi XFA SOM özellikleri desteklenmez?
losLab PDF Kütüphanesi'ndeki SOM desteği, veri kümeleri ve şablon alan yolları ile sınırlıdır ve sınırlar elinden gelenin en iyisini yapmak yerine kesin olarak belirlenmiştir. Bunları önceden bilmek, sessizce boş bir dize döndüren bir yolu hata ayıklamaktan kurtarır
- Koşul ifadeleri (predicates) keyfi FormCalc veya JavaScript çalıştırması yapmaz: İşlev çağrısı (bir
contains(...)koşulu boş döner), bileşik mantıksal ifadeler yoktur, yalnızca tek birçocuk operatör sabitkarşılaştırması vardır $recordyalnızca kayıt dışı işlem paketlerinde çalışır; dataWindow kayıt sayfalama ve kayıt grubu döndürme uygulanmamıştır- Çözümleme doğrudan Data DOM ve şablon DOM'una karşı yapılır; bir görüntüleyicinin çalışma zamanında oluşturduğu birleştirilmiş görünüm olan Form DOM göreli çözümlemesi gerçekleştirilmez
- Data DOM öznitelik yükleme semantikleri uygulanmaz; kütüphane veri kümeleri paketini ham XML olarak okur, bu nedenle yollar düğümlere yükseltilmiş öznitelikleri değil, öğeleri adresler
Bu sınırlar toplu doldurma işinde nadiren sıkıntı yaratır, çünkü doldurucu verileri betik mantığı yerine yapıya göre adresler. Sorun çıktığında kaçış kapısı paket düzeyidir: Tüm veri kümeleri XML'ini okuyun, Delphi'de dönüştürün ve geri yazın
SetXFAFromString ile tüm paketi yazma
SetXFAFromString paket düzeyindeki giriş noktasıdır: Şablon ve veri kümeleri dahil olmak üzere eksiksiz bir XDP dizgesini birlikte yükler ve henüz mevcut olmadığında yeni bir belgede AcroForm kapsayıcısını oluşturur; UTF-8'in yanı sıra bayt sırası işaretleri (BOM) olan UTF-16 kodlu paketleri de kabul eder. Yaygın bir üretim şekli, kurum tarafından verilen XDP'yi test verisi (fixture) olarak tutmak, SetXFAFromString ile yüklemek ve ardından kaydetmeden önce geçici fatura başına değerler için SOM adresli SetXFAFormFieldValue çağrılarını çalıştırmaktır. XFA, bir PDF'in taşıyabileceği iki form anlamından biri olduğundan, klasik AcroForm tarafının etkileşimli form eylemleri ve JavaScript hakkındaki makalede ele alınan kendi otomasyon hikayesi vardır
Burada gösterilen XFA alan-değer, numaralandırma ve paket API'leri, Delphi, C# ve VB.NET için losLab PDF Kütüphanesi içinde gönderilmektedir; ürün sayfası tam form işleme referansını taşımaktadır