مقالة تقنية

تعبيرات مسار XFA SOM في دلفي: بيانات النماذج الديناميكية

تقرأ وتكتب مكتبة losLab PDF Library عقد البيانات المتكررة في نماذج XFA الديناميكية من خلال تعبيرات مسار XFA 3.3 SOM: تقبل GetXFAFormFieldValue وSetXFAFormFieldValue الجذور $data، و$record، و!data، والرموز البديلة للتكرار [*]، ومحددات الفروع ومحددات الأبناء البديلة، والخاصية parent، ومحددات الفئات #dataGroup/#dataValue، والمسندات البسيطة بأسلوب FormCalc، بحيث يمكن لبرنامج دلفي تحديث كل سطر فاتورة في نموذج ضريبي حكومي باستدعاء واحد. هذه المقالة هي مرجع العنصرة؛ ولنقل مجموعات البيانات بأكملها بين الملفات، راجع المقالة المصاحبة حول تبادل بيانات نماذج FDF وXFDF وXFA

تظهر المشكلة في اللحظة التي يتوقف فيها النموذج عن كونه مسطحاً. فالإقرار الضريبي أو البيان الجمركي البيان الجمركي المبني كنموذج XFA ديناميكي لا يحتوي على اثني عشر حقلاً مسمى من Total_Price_1 إلى Total_Price_12؛ بل يحتوي على نموذج فرعي واحد Detail يتم التصريح عنه مرة واحدة في نموذج DOM للقالب ويتم إنشاؤه لعدد من المرات تفرضه البيانات. تعيش القيم في شجرة ثانية، وهي Data DOM داخل حزمة مجموعات البيانات، حيث كل عنصر سطر هو عنصر <Detail> متكرر تحت <Receipt>. لا يمكن لأسماء الحقول المسطحة معالجة "السعر في السطر الثالث" أو "كل سطر يزيد عن 200"؛ وهذه هي بالضبط المهمة التي يمنحها فصل Scripting Object Model من مواصفات Adobe XFA 3.3 لتعبيرات SOM، وهي الصيغة التي تتحدث بها واجهات برمجة تطبيقات قيم حقول XFA لمكتبة losLab PDF Library

كيف تقوم بعنونة عقد بيانات XFA من دلفي؟

يبدأ كل مسار لمجموعات البيانات من جذر، وتقبل مكتبة losLab PDF Library الهجاءات القياسية بشكل متبادل: $data هو الشكل القصير لـ XFA 3.3 من xfa.datasets.data، و!data هو الشكل القصير المتجذر في xfa.datasets، وفي الحزم التي لا تستخدم معالجة السجلات، يتم حل $record إلى سجل البيانات الخارجي، وهو العنصر الأول تحت عقدة البيانات. تقبل واجهات برمجة التطبيقات من جانب القالب مثل SetXFAFormFieldAccess كلاً من $template وxfa.template بنفس الطريقة. قد تكون الأجزاء محددة بنقاط أو بشرطات مائلة ($data.Receipt.Tax أو $data/Receipt/Tax)، وهو أمر مهم لأن GetXFAFormFieldNames يعدد الحقول كمسارات محددة بشرطة مائلة تغذي مباشرة واجهات برمجة تطبيقات القيم والقالب. تكون فهارس التكرار قائمة على الصفر وفقاً للمواصفات، لذا فإن Detail[0] هو الصف الأول. تحافظ قاعدتا هروب على إمكانية عنونة الأسماء غير العادية: ففي مسار محدد بنقاط، يرمز \. إلى نقطة حرفية (Line\.Item)، بينما تعامل المسارات المحددة بشرطة مائلة النقاط كأحرف عادية. تتم مطابقة بيانات الأعمال التي تحمل بادئة مساحة اسم XML الخاصة بها بالاسم المحلي، لذا لا تزال <m:Receipt> تستجيب لـ Receipt

var
  Lib: TPDFlib;
  Tax: WideString;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('vat-return.pdf', '');
    // Equivalent addresses for the same data node
    Tax := Lib.GetXFAFormFieldValue('Receipt.Tax');
    Tax := Lib.GetXFAFormFieldValue('$data.Receipt.Tax');
    Tax := Lib.GetXFAFormFieldValue('xfa.datasets.data.Receipt.Tax');
    Tax := Lib.GetXFAFormFieldValue('$record.Tax');
    // Slash form with a zero-based occurrence index
    Lib.SetXFAFormFieldValue('$record/Detail[0]/Total_Price', '251.00');
    Lib.SaveToFile('vat-return-updated.pdf');
  finally
    Lib.Free;
  end;
end;

كيف تقوم بتعبئة الصفوف المتكررة في نموذج XFA برمجياً؟

الرمز البديل للتكرار [*] هو أداة الدفعات. حيثما يحدد الفهرس الرقمي شقيقاً واحداً، يحدد [*] جميع الأشقاء الذين يحملون نفس الاسم، وبالتالي يعالج $data.Receipt.Detail[*].Total_Price حقل السعر في كل عنصر سطر دفعة واحدة. عند القراءة، تعيد GetXFAFormFieldValue قيم جميع العقد المتطابقة مدمجة بفاصل |؛ وعند الكتابة، تحدث SetXFAFormFieldValue كل عقدة متطابقة بنفس القيمة وتعيد 1 عند النجاح. يقرأ المسار الذي لا يطابق أي شيء كأنه سلسلة فارغة، وهي الطريقة السهلة لاستكشاف ما إذا كان الفرع موجوداً قبل الكتابة فيه

var
  Lib: TPDFlib;
  Prices: WideString;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('invoice.pdf', '');
    // All Detail rows at once: '250.00|60.00'
    Prices := Lib.GetXFAFormFieldValue('$data.Receipt.Detail[*].Total_Price');
    // Reset one column across every repeated row in a single call
    Lib.SetXFAFormFieldValue('$data.Receipt.Detail[*].Surcharge', '0.00');
    Lib.SaveToFile('invoice-updated.pdf');
  finally
    Lib.Free;
  end;
end;

محددات الفروع والأبناء البديلة والآباء

تغطي ثلاثة محددات هيكلية الحالات التي تعرف فيها اسم الحقل ولكن ليس عمقه الدقيق. يطابق محدد الفرع .. يطابق عند أي عمق تحت العقدة الحالية: يجد $data..Total_Price أول Total_Price في أي مكان تحت جذر البيانات، وتحدث الكتابة عبر مسار فرعي تلك العقدة المتطابقة الأولى. لاحظ الحد: فهرس التكرار بعد مطابقة الفرع لا يخطو عبر فروع الأشقاء، فإذا تم حل $data..Total_Price[0] داخل صف Detail الأول، يعيد $data..Total_Price[1] قيمة فارغة بدلاً من القفز إلى الصف التالي؛ استخدم Detail[*] عندما تريدهم جميعاً. يطابق الرمز البديل للابن .* كل ابن مباشر ويسمح للأجزاء المتبقية بالتصفية: يصل $data.Receipt.*.Total_Price إلى Total_Price داخل كل فرع ابن لـ Receipt دون تحديد حقل ملخص يحمل نفس الاسم ويقع مباشرة على Receipt نفسها. أخيرًا، تتسلق الخاصية parent مستوى واحداً، وهو ما يفصله XFA 3.3 عمداً عن ..: حيث يبدأ $data.Receipt.Detail[1].parent.Tax عند عنصر السطر الثاني، ويصعد إلى Receipt، ويهبط على قيمة شقيقه Tax

محددات الفئات والمسندات: #dataGroup، و#dataValue، و.[expression]

تعالج صيغة #class عقد Data DOM بواسطة فئة الكائن بدلاً من الاسم، وهو المسار العملي عندما تحتوي علامات XML على أحرف يصعب تهجئتها كأسماء برمجة نصية. تعين مكتبة losLab PDF Library كلاً من #dataGroup للعناصر التي لها أبناء عناصر و#dataValue للعناصر الورقية التي ليس لها أبناء عناصر، وتتحد كلتاهما مع تكرارات رقمية أو [*]: يحدد $data.Receipt.#dataGroup[0].#dataValue[0] القيمة الأولى داخل المجموعة الأولى تحت Receipt. يقوم محدد المسند .[expression] بتصفية الأشقاء الذين يحملون نفس الاسم حسب المحتوى. المسندات المدعومة هي مقارنات بسيطة لقيمة ابن مقابل قيمة حرفية، مع معاملات علائقية مثل >، و<، و<=؛ وعندما يطابق المسند عدة صفوف، تأتي القراءات مدمجة بـ | وتحدث الكتابة كل مطابقة

// Flag every line whose Total_Price exceeds 200
Lib.SetXFAFormFieldValue(
  '$data.Receipt.Detail.[Total_Price > 200].Review_Flag', '1');

// Descriptions of all low-value lines, '|'-joined when several match
Desc := Lib.GetXFAFormFieldValue(
  '$data.Receipt.Detail.[Total_Price <= 200].Description');

// Class-based addressing when tag names resist script spelling
Total := Lib.GetXFAFormFieldValue(
  '$data.Receipt.#dataGroup[0].#dataValue[0]');

ما هي ميزات XFA SOM غير المدعومة؟

ينحصر دعم SOM في مكتبة losLab PDF Library في مجموعات البيانات ومسارات حقول القوالب، وتكون الحدود صريحة وليست بأفضل جهد. معرفتها مسبقاً توفر استكشاف أخطاء مسار يعيد بصمت سلسلة فارغة

  • لا تنفذ المسندات تعبيرات FormCalc أو JavaScript عشوائية: لا توجد استدعاءات دوال (يعيد مسند contains(...) قيمة فارغة)، ولا تعبيرات منطقية مركبة، فقط مقارنة child op literal واحدة
  • يعمل $record في الحزم التي لا تستخدم معالجة السجلات فقط؛ ولا يتم تنفيذ تقسيم سجلات dataWindow وتدوير مجموعة السجلات
  • يكون الحل مقابل Data DOM وtemplate DOM مباشرة؛ ولا يتم تنفيذ الحل النسبي لـ Form DOM، وهو العرض المدمج الذي يبنيه العارض في وقت التشغيل
  • لا يتم تطبيق دلالات تحميل سمات Data DOM؛ تقرأ المكتبة حزمة مجموعات البيانات كملف XML خام، لذا تعنون المسارات العناصر، وليس السمات التي تمت ترقيتها إلى عقد

نادراً ما تسبب هذه الحدود مشاكل في أعمال التعبئة المجمعة، لأن المعبئ يعنون البيانات حسب الهيكل وليس حسب المنطق المكتوب. وعندما تفعل ذلك، فإن مخرج الطوارئ هو على مستوى الحزمة: اقرأ كامل ملف XML لمجموعات البيانات، وقم بتحويله في دلفي، واكتبه مرة أخرى

كتابة الحزمة بأكملها باستخدام SetXFAFromString

تعتبر SetXFAFromString هي نقطة الدخول تلك على مستوى الحزمة: فهي تثبت سلسلة XDP كاملة، القالب ومجموعات البيانات معاً، وتنشئ حاوية AcroForm في مستند جديد عندما لا يوجد أي منها بعد، وتقبل الحزم المشفرة بـ UTF-16 مع علامات ترتيب البايت وكذلك UTF-8. الشكل الشائع في الإنتاج هو الاحتفاظ بملف XDP الصادر عن الجهة الرسمية كثابت، وتحميله باستخدام SetXFAFromString, ثم تشغيل استدعاءات SetXFAFormFieldValue المعنونة بـ SOM للقيم المتقلبة لكل فاتورة قبل الحفظ. ونظراً لأن XFA هو أحد نموذجي النماذج التي يمكن لملف PDF حملها، فإن لجانب AcroForm الكلاسيكي قصة أتمتة خاصة به، مغطاة في مقالة إجراءات النماذج التفاعلية وJavaScript

تُشحن واجهات برمجة تطبيقات قيم الحقول والتعداد والحزم لـ XFA الموضحة هنا في losLab PDF Library لدلفي، وC# وVB.NET؛ وتتميز صفحة المنتج بمرجع معالجة النماذج الكامل