從語意內容輸出帶標記的 PDF/UA-2 結構樹
這則 recipe(範例)會產生一份以 ISO 14289-2(PDF/UA-2)為目標的帶標記 PDF。NextPDF 會輸出邏輯結構樹、標記內容序列、目錄語言設定,以及文件層級的識別中繼資料。這套結構支援無障礙撰寫,但符合性仍由獨立檢查工具判定。這則範例依循 examples/31-pdfua2-tagged.php。
composer require nextpdf/core:^3驗證步驟需要在 PATH 上找到 PDF/UA-2 檢查工具。本範例使用搭配 ua2 設定檔的 veraPDF。你不需要 Pro 或 Enterprise 套件,就能輸出帶標記的結構。
觀念概述
標題為「觀念概述」的區段帶標記的 PDF 會在視覺內容串流之外,並行攜帶一棵 邏輯結構樹。輔助科技讀取的是這棵樹,而不是像素佈局,因此結構會決定對外揭露的閱讀順序。ISO 14289-2 在此定義了四項要求:真實(非 artifact)內容必須能透過這棵樹觸及(§8.2.2);結構元素必須依已定義的順序巢狀(§8.2.3);每個元素都必須 resolve(解析)到已知的結構命名空間,可以直接對應,也可以透過角色對映(§8.2.4);內容的自然語言必須在文件層級宣告,並在語言不同的結構元素上逐一細化(§8.4.4)。
NextPDF 以具型別的 ConformanceMode 建模這項行為。enableTaggedPdf() 會設定 ConformanceMode::PdfUa2,並且(a)讓 HTML 管線在 parser(剖析器)建構時接上 TaggedContentEmitter、(b)啟用代表帶標記 PDF 的目錄 MarkInfoMarked 旗標(ISO 32000-2 §14.7),以及(c)在目錄 Lang 項目記錄 BCP-47 語言。writer 也會輸出每頁的 Tabs 項目,讓 Tab 順序跟隨結構順序(ISO 32000-2 §14.8)。
嚴格的 UA-2 不變量只套用於 ConformanceMode::PdfUa2。在任何其他模式下建構嚴格的 ConformancePolicy,依設計都會擲出 InvalidConfigException。
API 介面
標題為「API 介面」的區段API 介面由 PHPDoc 產生。核心功能的進入點如下:
\NextPDF\Core\Document::createStandalone(): DocumentDocument::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): staticDocument::setLanguage(string $lang): static\NextPDF\Conformance\ConformancePolicy::strictUa2(): self\NextPDF\Conformance\ConformanceMode::PdfUa2(由enableTaggedPdf()設定的模式)Document::beginTag(string $type): static/Document::endTag(): static(為非 HTML 內容手動加標記)
程式碼範例 — 快速上手
標題為「程式碼範例 — 快速上手」的區段<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// Enable tagged mode BEFORE writeHtml(). The HTML pipeline detects the// mode at parser construction time and wires the tagged-content emitter.$doc->enableTaggedPdf(lang: 'en');
$doc->setTitle('Quarterly Accessibility Report');$doc->setLanguage('en');$doc->addPage();
$doc->writeHtml(<<<'HTML'<h1>Quarterly Accessibility Report</h1><p>This document opts into tagged PDF so assistive technology can exposea meaningful reading order.</p><ul> <li>Headings carry semantic roles.</li> <li>Lists keep their item structure.</li></ul>HTML);
$doc->save(__DIR__ . '/output/31-pdfua2-tagged.pdf');
echo "Created: output/31-pdfua2-tagged.pdf\n";程式碼範例 — 正式環境
標題為「程式碼範例 — 正式環境」的區段這是一支自成一體、可由測試載具執行的程式。正式環境的呼叫端會在語言標籤格式不正確時快速失敗,而不是等到外部檢查工具執行時才發現。傳入 ConformancePolicy::strictUa2() 後,就能在 API 邊界拒絕無效的 BCP-47 標籤,再以檢查工具的判定把關建置。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Conformance\ConformancePolicy;use NextPDF\Core\Document;use NextPDF\Exception\InvalidConfigException;
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: (__DIR__ . '/accessible.pdf');
try { $doc = Document::createStandalone();
// Strict UA-2: a malformed BCP 47 tag throws here, not silently at // write time. strictUa2() also forces the §8.4.4 Lang validation. $doc->enableTaggedPdf(lang: 'en-GB', policy: ConformancePolicy::strictUa2());
$doc->setTitle('Accessible Annual Report 2026'); $doc->setLanguage('en-GB'); $doc->addPage();
$doc->writeHtml(<<<'HTML'<h1>Annual Report 2026</h1><p>Audited results for the financial year ending March 2026.</p><h2>Segment performance</h2><table> <tr><th>Segment</th><th>Revenue</th></tr> <tr><td>Cloud</td><td>42.1</td></tr> <tr><td>Services</td><td>18.7</td></tr></table>HTML);
$doc->save($out);} catch (InvalidConfigException $e) { fwrite(STDERR, "Tagged PDF/UA-2 setup rejected: {$e->getMessage()}\n"); exit(1);}
// The gate is the checker, not the library.$exitCode = 0;$report = [];exec('verapdf --flavour ua2 ' . escapeshellarg($out), $report, $exitCode);
if ($exitCode !== 0) { fwrite(STDERR, "veraPDF FAILED — output is not PDF/UA-2 conforming\n"); fwrite(STDERR, implode("\n", $report) . "\n"); exit(1);}
echo "veraPDF PASS — accessible.pdf carries a conforming UA-2 structure\n";在 verapdf --flavour ua2 回報檔案符合的主機上,預期 STDOUT 為:
veraPDF PASS — accessible.pdf carries a conforming UA-2 structure如果 enableTaggedPdf() 拒絕該語言標籤,程式會在 STDERR 印出 Tagged PDF/UA-2 setup rejected: … 後,以非零碼結束。如果檢查工具回報問題,程式會在印出 veraPDF FAILED — output is not PDF/UA-2 conforming 後,以非零碼結束。判定權在檢查工具:NextPDF 只輸出結構,不宣稱符合性。
邊界情況與陷阱
標題為「邊界情況與陷阱」的區段- 呼叫順序。 如果在
writeHtml()之後才呼叫enableTaggedPdf(),它不會追溯地為已寫入的內容加標記。請先啟用帶標記模式。 - 嚴格語言把關。 沒有政策時,無法剖析的 BCP-47 標籤會被靜默丟棄,直到檢查工具執行時才浮現。加上
ConformancePolicy::strictUa2()後,同一個標籤會在enableTaggedPdf()邊界擲出InvalidConfigException(ISO 14289-2 §8.4.4 嚴格路徑)。 - 可重複啟用。 呼叫
enableTaggedPdf()兩次會更新語言,但不會重建已填入的結構樹。 - 手動加標記。 對非 HTML 內容,請用
beginTag()/endTag()將項目包起來。容器角色(Table、TR、L、LI)會成為沒有標記內容的分組元素。葉節點角色(P、H1–H6、TD)則會取得 MCID。 - 模式互斥。 嚴格的
ConformancePolicy只在ConformanceMode::PdfUa2下有效。將嚴格 UA-2 旗標與 PDF/A 模式組合在一起會擲出InvalidConfigException。若要產生帶標記的 PDF/A 交付物,請分別啟用帶標記模式與 PDF/A 設定檔。
結構樹會額外加入一棵由輕量字典組成的並行樹,並為每段文字執行 BDC/EMC 運算子。以典型報告來說,這項額外開銷只佔輸出大小的幾個百分比,且穩定落在 2000 ms / 128 MB 預算之內。語意可重現性設定檔在這裡適用,因為以檢查工具為導向的交付物,是用結構抽象語法樹(AST)加上中繼資料來比對,而不是用原始位元組。請參閱「符合性」一節。
安全性注意事項
標題為「安全性注意事項」的區段靜態資料與 PII 緩解措施
標題為「靜態資料與 PII 緩解措施」的區段結構樹攜帶的文字與可見內容相同。如果來源 HTML 含有個人資料,那些資料也能透過這棵樹,以及透過 ActualText/Alt 屬性被觸及。請在撰寫前,套用與可見內容相同的遮蔽與最小化處理。加標記不會新增外洩管道,但依設計會讓文字可被程式擷取。
安全遙測與日誌清洗
標題為「安全遙測與日誌清洗」的區段這則範例只會向 STDOUT 寫出一行固定的進度訊息。它會將 PDF 導向測試載具的旁路通道(NEXTPDF_COOKBOOK_OUTPUT),或導向呼叫端指定的路徑。文件文字絕不會寫入日誌。可能回傳內容片段的檢查工具輸出,請排除在共用日誌之外。
威脅模型
標題為「威脅模型」的區段帶標記的 PDF 不是信任邊界。信任結構樹進行自動化處理的消費端仍必須驗證該檔案,因為惡意產生端可以輸出一棵結構格式正確、但具有誤導性的樹。請把這套結構視為無障礙輔助手段,而不是完整性或真實性的訊號。
FIPS 模式行為
標題為「FIPS 模式行為」的區段這則範例不執行任何密碼學運算。FIPS 模式不會改變它的行為。不涉及任何簽章或加密。
PDF/UA-2 對映
標題為「PDF/UA-2 對映」的區段| PDF/UA-2 要求 | NextPDF 輸出的內容 | 條款 |
|---|---|---|
| 真實內容位於結構樹中 | StructTreeRoot,搭配各區塊的 StructElem 與以 MCID 連結的標記內容 | ISO 14289-2 §8.2.2 |
| 已定義的巢狀關係與閱讀順序 | 區塊元素依文件順序對映到 grouping/leaf 角色 | ISO 14289-2 §8.2.3 |
| 已知的結構命名空間 | 角色位於 PDF 2.0 命名空間;HTML 標籤在需要時會做角色對映 | ISO 14289-2 §8.2.4 |
| 文件與元素的語言 | 目錄 Lang 取自 BCP-47 標籤;每個元素的 Lang 會在語言不同時各自帶上 | ISO 14289-2 §8.4.4 |
| 非文字內容帶有文字替代 | Alt/ActualText 附在 figure/non-text 結構元素上 | ISO 14289-2 §8.5.1 |
| 表格關係 | Table/TR/TH/TD 角色,並帶表頭關聯 | ISO 14289-2 §8.2.5.26 |
| 部分識別中繼資料 | 文件層級的識別資訊會排定於儲存時寫入 | ISO 14289-2 §引言(pdfua2#p17) |
標籤 → ISO 32000-2 §14 交叉參照
標題為「標籤 → ISO 32000-2 §14 交叉參照」的區段PDF/UA-2 將無障礙要求疊加在 ISO 32000-2 的帶標記 PDF 機制之上。NextPDF 依賴的對映如下:
| NextPDF 輸出 | ISO 32000-2 §14 機制 | 條款 |
|---|---|---|
邏輯結構樹(StructTreeRoot) | 帶標記 PDF 的邏輯結構 | §14.7 (iso32000_2_sec14#x1.x38.p13) |
目錄 MarkInfo << /Marked true >> | 帶標記 PDF 的標記旗標 | §14.7 (iso32000_2_sec14#x1.x40.p3) |
每頁的 Tabs 項目,依循結構順序 | 結構導覽/Tab 順序 | §14.8 (iso32000_2_sec14#x1.x50) |
WCAG 2.2 對映
標題為「WCAG 2.2 對映」的區段PDF/UA-2 是 WCAG 2.2 以格式無關方式陳述的結構要求在 PDF 格式中的具體表達。相關對應如下:
| WCAG 2.2 成功準則 | 這則範例產生的 PDF/UA-2 機制 |
|---|---|
| 1.3.1 資訊與關係(Level A) | 結構樹讓標題、清單與表格關係能由程式判定(wcag_2_2#x2.x3.x3.x1.p3)。 |
| 1.3.2 有意義的順序(Level A) | 結構順序定義了不受視覺佈局影響的閱讀順序。 |
| 3.1.1 頁面語言(Level A) | 取自 BCP-47 標籤的目錄 Lang 項目。 |
| 1.1.1 非文字內容(Level A) | Alt/ActualText 附在非文字結構元素上(ISO 14289-2 §8.5.1)。 |
這份對映說明輸出的結構在哪些位置支援各項 WCAG 2.2 準則。它不是 WCAG 符合性聲明。WCAG 符合性涵蓋整體使用者體驗,應由無障礙評估判定,而非由產生端決定。
符合性
標題為「符合性」的區段| 陳述 | 規範 | 條款 | 參考 ID |
|---|---|---|---|
| 真實內容需要邏輯結構。 | ISO 14289-2 | §8.2.2 | |
| 結構元素遵循已定義的巢狀與閱讀順序。 | ISO 14289-2 | §8.2.3 | |
| 每個結構元素都會解析到一個已知的命名空間,可直接對應,也可透過角色對映。 | ISO 14289-2 | §8.2.4 | |
| 自然語言會在文件層級與結構元素層級宣告。 | ISO 14289-2 | §8.4.4 | |
| 非文字內容帶有文字替代。 | ISO 14289-2 | §8.5.1 | |
| 表格儲存格帶有 row/header/資料關係。 | ISO 14289-2 | §8.2.5.26 | |
帶標記 PDF 的標記由目錄 MarkInfoMarked 旗標表示。 | ISO 32000-2 | §14.7 | |
| 符合性依該部分標準判定,而非由產生端宣稱。 | ISO 14289-2 | §8.14.2 |
NextPDF 會輸出支援無障礙撰寫的帶標記結構。**支援不等於符合。**這則範例並不宣稱 PDF/UA-2 符合性。這項判定由獨立檢查工具(例如 veraPDF)執行。在宣稱某個檔案符合之前,請先執行檢查工具。