تخطَّ إلى المحتوى

إمكانية الوصول: عناصر الوسم الأساسية ونموذج بنية PDF/UA-2

يوفّر ⁨NextPDF Core⁩ عناصر أساسية للتأليف المتاح: شجرة بنية منطقية، وتعيين أدوار قياسي، ووسم محتوى معلَّم، وسمات لغة وفق أفضل ممارسة حالية (⁨BCP⁩) 47 بما يتوافق مع نموذج شجرة البنية في ⁨ISO 14289-2⁩ (⁨PDF/UA-2⁩) و⁨ISO 32000-2⁩ §14.7. لا يكون الملف الناتج متوافقًا إلا عندما يدعم المستند النهائي، وخيارات المحتوى التي يحددها المؤلف، وأداة فحص خارجية هذه النتيجة. لا تؤكّد المكتبة هذا الضمان نيابةً عنك.

Terminal window
composer require nextpdf/core

يتضمّن ملف تنسيق المستندات المحمولة (⁨PDF⁩) الموسوم شجرة بنية منطقية يحمل جذرها عنصر بنية Document وحيدًا. تقرأ التقنيات المساعِدة تلك الشجرة لتحديد ترتيب قراءة ذي معنى لا يعتمد على التخطيط المرئي (⁨ISO 32000-2⁩ §14.7.2؛ ⁨ISO 14289-2⁩ §8.2.5.2). يُنمذِج ⁨NextPDF⁩ ذلك عبر ثلاثة أنواع متعاونة في مساحة الأسماء NextPDF\Accessibility.

يمتلك StructureTree التسلسل الهرمي. فهو يخصّص معرّفات المحتوى المعلَّم لكل صفحة، ويتتبّع تداخل الأصل والفرع، ويسلسل جذر شجرة البنية، وعناصر البنية، وشجرة الأصل، وخريطة الأدوار، ومساحة أسماء البنية القياسية في ⁨PDF 2.0⁩ وفق ⁨ISO 32000-2⁩ §14.7. ينشئ createRoot() عنصر Document الوحيد الإلزامي مع سمة لغة. يربط addElement() العناصر الفرعية ذات النوع المحدّد. ويُبلغ hasRoot() وrootHasChildren() عمّا إذا كانت الشجرة موجودة وعمّا إذا كان لها نسل.

StructureElement هو كائن القيمة لقاموس عنصر بنية واحد. يخزّن نوع البنية القياسي (أسماء الجدول 368 مثل H1 حتى H6، وP، وL، وLI، وTable، وFigure، وLink)، ومدخلات معرّف المحتوى المعلَّم، وسمات إمكانية الوصول الاختيارية للنص البديل، والنص البديل التعويضي، والعنوان، واللغة. يمكن لعنصر واحد أن يمتد عبر صفحات متعددة. لذلك يجمع مدخل معرّف واحدًا لكل صفحة، بحيث تشير مصفوفة العناصر الفرعية إلى المحتوى المعلَّم عبر حدود الصفحات.

يربط TaggedContentEmitter خط أنابيب لغة ترميز النص الفائق (⁨HTML⁩) بشجرة البنية. عندما يكون Document::enableTaggedPdf() فعّالًا، يوصِّل مُصيِّر ⁨HTML⁩ المُصدِر بحيث تُنشئ العناصر على مستوى الكتلة عوامل محتوى معلَّم مزدوجة وعُقد عنصر بنية مطابِقة. يوفّر HtmlToStructureMap تعيينًا جدوليًا من وسوم ⁨HTML⁩ إلى أنواع بنية ⁨PDF⁩ (⁨ISO 14289-2⁩ §8). يوجّه المُصدِر المحتوى الجاري الزخرفي، مثل منطقتي ترويسة ⁨HTML⁩ وتذييلها، إلى قِطعة أثرية ويُبقيه خارج ترتيب القراءة.

يتحقق Bcp47Validator من وسم اللغة (طلب التعليقات (⁨RFC⁩) 5646). يوفّر فحصًا نحويًا لصحة التكوين وفحص صلاحية مدعومًا بالسجل. يرفض الوضع الصارم (ConformancePolicy::strictUa2()) الوسوم المشوّهة عند حدود واجهة برمجة التطبيقات (⁨API⁩) بدل إسقاطها بصمت وقت الكتابة. يطابق ذلك متطلب ⁨ISO 14289-2⁩ §8.4.4 القاضي بأن يُحَلّ مدخل لغة الفهرس إلى لغة محددة.

الرمزالنوعالملخّص
Document::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): staticدالةتفعّل شجرة البنية وجسر ⁨HTML⁩؛ وتضبط مدخلات معلومات الوسم ولغة الفهرس.
Document::setLanguage(string $lang): staticدالةتضبط اللغة الطبيعية على مستوى المستند (⁨BCP 47⁩).
Document::isTaggedPdfEnabled(): boolدالةتُبلغ عمّا إذا كان وضع التوافق الفعّال يفرض الوسم البنيوي.
StructureTree::createRoot(string $lang = 'en'): intدالةتنشئ عنصر الجذر Document الوحيد الإلزامي.
StructureTree::addElement(int $parentIndex, string $type, int $pageIndex, ...): intدالةتربط عنصر بنية فرعيًا ذا نوع محدّد.
StructureTree::hasRoot(): bool وrootHasChildren(): boolدالةتُبلغ عمّا إذا كانت الشجرة موجودة وعمّا إذا كان لها نسل.
StructureElementصنف نهائيكائن قيمة لعنصر بنية واحد (النص البديل، والنص البديل التعويضي، والعنوان، واللغة، والمعرّفات).
RoleMap::standard(): array<string,string>ثابتيُرجع مفردات نوع البنية القياسية (⁨ISO 32000-2⁩ الجدول 368 بالإضافة إلى أنواع ⁨PDF 2.0⁩).
Bcp47Validator::isWellFormed/isValid/validate/normaliseدالةيتحقق من وسوم لغة ⁨RFC 5646⁩ بفحوص نحوية ومدعومة بالسجل.
AccessibilityAutoFixerRegistryصنف نهائيسجل اختياري على نمط توصية معايير ⁨PHP⁩ (⁨PSR⁩)-11 لأدوات إصلاح البنية الاستدلالية.

عيّنة شيفرة — البدء السريع

قسم بعنوان «عيّنة شيفرة — البدء السريع»
<?php
declare(strict_types=1);
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// The BCP 47 tag drives the catalog language entry and the
// structure-tree root language attribute.
$doc->enableTaggedPdf(lang: 'en');
$doc->setTitle('Tagged accessibility demo');
$doc->addPage();
// Semantic HTML maps to structure elements: h1 to /H1, p to /P,
// ul and li to /L plus /LI. Text runs are wrapped in
// marked-content operators with stable identifiers.
$doc->writeHtml('<h1>Document title</h1><p>Body paragraph.</p>');
$doc->save(__DIR__ . '/output/tagged.pdf');
<?php
declare(strict_types=1);
use NextPDF\Conformance\ConformancePolicy;
use NextPDF\Core\Document;
use NextPDF\Exception\InvalidConfigException;
use Psr\Log\LoggerInterface;
final class AccessibleReportWriter
{
public function __construct(private readonly LoggerInterface $logger)
{
}
public function render(string $html, string $bcp47Lang, string $outPath): void
{
$doc = Document::createStandalone();
try {
// strictUa2() rejects malformed BCP 47 tags at the API
// boundary (ISO 14289-2 §8.4.4) instead of dropping silently.
$doc->enableTaggedPdf($bcp47Lang, ConformancePolicy::strictUa2());
} catch (InvalidConfigException $e) {
$this->logger->error('Rejected language tag for tagged PDF', [
'lang' => $bcp47Lang,
'reason' => $e->getMessage(),
]);
throw $e;
}
$doc->setTitle('Quarterly accessibility report')
->setLanguage($bcp47Lang)
->addPage();
$doc->writeHtml($html);
// The engine emits a Degraded / ComplianceRisk advisory directing
// the caller to validate externally; surface it to operators
// rather than treating tagged output as certified.
foreach ($doc->getWarnings() as $warning) {
$this->logger->warning('Tagged-PDF advisory', [
'code' => $warning->code->value,
'message' => $warning->message,
]);
}
$doc->save($outPath);
}
}
  • ترتيب الاستدعاءات. استدعِ enableTaggedPdf() قبل writeHtml(). يفحص خط أنابيب ⁨HTML⁩ وضع التوافق عند إنشاء المحلّل، ولا يوصّل المُصدِر بأثر رجعي للمحتوى الذي سبق تصييره.
  • شجرة بنية فارغة. المستند الذي يحتوي على enableTaggedPdf() لكن لا يتضمن نسل بنية مرفقًا لا يُعلِن عن ⁨PDF/UA-2⁩ في بياناته الوصفية. بوابة النشر هي rootHasChildren()، وليست hasRoot()، لأن أدوات التحقق ترفض ملفًا يدّعي ⁨PDF/UA-2⁩ مع شجرة بنية فارغة (⁨ISO 14289-2⁩ §5؛ تحقّق منه EmptyTaggedPdfDoesNotAdvertisePdfUa2Test).
  • انهيار وضع التوافق. عندما تستدعي enablePdfA() وenableTaggedPdf() على المستند نفسه، ينهار مميِّز التوافق أحادي القيمة وفق مبدأ أن آخِر استدعاء هو الذي يفوز. تبقى الآثار الجانبية (شجرة البنية، ومعلومات الوسم) تراكمية، ويُصدِر ⁨NextPDF⁩ تحذير CONFORMANCE_MODE_CLOBBERED بحيث يكون الانهيار قابلًا للملاحظة.
  • أدوات الإصلاح التلقائي ليست تلقائية. أدوات الإصلاح المدمجة (EmptyTagStripper، وLegacyLangNormaliser، وRootLangFallback) تُشحَن ضمن NextPDF\Accessibility\AutoFixer\*، لكنها لا تُسجَّل تلقائيًا أبدًا. يجب عليك تسجيلها صراحةً على AccessibilityAutoFixerRegistry.

يُصدِر ⁨NextPDF⁩ بنيةً متسقة مع نموذج شجرة بنية ⁨PDF/UA-2⁩، لكنه لا يُنشئ دلالات لا يستطيع استنتاجها. يجب عليك توفير الترميز أو السمات لما يلي؛ إذ إن ⁨NextPDF⁩ لا يُولّدها نيابةً عنك:

  • النص البديل للصور وغيرها من المحتوى غير النصي؛
  • نطاق ترويسة الجدول وارتباطات الترويسة بالخلية بما يتجاوز ما يعبّر عنه ترميز ⁨HTML⁩؛
  • نص غرض الرابط عندما لا يكون نص الرابط المرئي وصفيًا لذاته؛
  • دلالات القائمة للمحتوى المرتَّب بصريًا على شكل قائمة لكنه يفتقر إلى ترميز القائمة؛
  • ترتيب القراءة المصحَّح عندما يختلف ترتيب المصدر عن ترتيب القراءة المقصود؛
  • تصنيف المحتوى الغامض بوصفه زخرفيًا أو هادفًا.

لا يُجري ⁨NextPDF⁩ أي تحقق شامل من ⁨PDF/UA-2.⁩ في وقت التشغيل. وبدلًا من ذلك، يُصدِر تنبيهًا من نوع متدهور / خطر توافق (PDFUA2_FOUNDATIONAL) يوجّه المستدعي إلى التحقق من المُخرَج بأداة فحص خارجية قبل الموافقة النهائية للإنتاج. تحقّق بأداة فحص ⁨PDF/UA⁩ (على سبيل المثال، ⁨veraPDF⁩). لا يؤكّد ⁨NextPDF⁩ التوافق نيابةً عنك. يعتمد توافق المستند النهائي على خيارات التأليف وأداة التحقق، لا على استدعاء ⁨API.⁩

بناء شجرة البنية خطّي بالنسبة إلى عدد عناصر البنية. تخصيص المعرّفات يستغرق زمنًا ثابتًا مُستهلَكًا لكل تسلسل محتوى معلَّم. أما التسلسل فهو تمريرة خطّية واحدة على مجموعة العناصر. بالنسبة إلى الوسم المُدار بـ ⁨HTML⁩، تكون التكلفة الغالبة في خط أنابيب ⁨HTML⁩ نفسه، لا في إصدار الوسوم. ينطبق الحد الأقصى لكل وصفة والمُعلَن في performance_budget (1500 ⁨ms⁩ زمن جدار، 64 ⁨MB⁩ ذروة) على مستند دلالي نموذجي متعدد الصفحات. تتوسّع المستندات الكبيرة خطّيًا مع عدد العناصر بدلًا من عدد الصفحات.

تتدفّق وسوم اللغة وسمات إمكانية الوصول إلى كائنات الاسم والنص في ⁨PDF.⁩ يهرّبها ⁨NextPDF⁩ عبر PdfStringEscaper، بحيث لا يمكن لقيم اللغة والنص البديل والنص البديل التعويضي والعنوان المشوّهة أو العدائية أن تخرج من سياق كائن ⁨PDF⁩ الخاص بها. يرفض الوضع الصارم أيضًا وسوم ⁨BCP 47⁩ غير المسجَّلة عند حدود ⁨API⁩، مما يضيّق سطح الإدخال قبل وصوله إلى الكاتب. يمكن لسمات إمكانية الوصول أن تحمل نصًا حرًا يقدّمه المؤلف. عامِلها كمُخرَج غير موثوق وراجِعها كما تراجع أي محتوى آخر في المستند. راجِع وحدة التوافق للاطّلاع على سلوك أداة فحص المِلَفّات الجانبية.

تربط هذه الصفحة سلوك المكتبة بمعرّفات البنود. وهي لا تؤكّد أن مُخرَجك متوافق. البنود المستشهَد بها مُعاد صياغتها، ولا تُقتبس حرفيًا أبدًا. راجِع تعيين مواصفة ⁨PDF/UA-2⁩ للاطّلاع على جدول مستوى الأحكام وبيان عدم التغطية الصريح. تُسجَّل تجزئات أجزاء الاستشهاد في docs/public/modules/core/_normative-evidence-a11y.md.