Ga naar inhoud

Ast: semantische documentboom en serialisatie

De Ast-module levert de semantische abstract syntax tree (AST) voor documenten in de engine. De module modelleert een document als een getypeerde knooppunthiërarchie: Document, Section, Heading, Paragraph, List, Table, Figure, Code en FormField. Het model registreert bounding boxes en citatieankers en serialiseert naar geversioneerde JavaScript Object Notation (JSON). De toegankelijkheidstagginglaag gebruikt deze boom om een structuurboom te produceren.

Stabiliteit: experimenteel. Dit is een intern modeloppervlak. De klassen ervan bieden geen versiebevroren publieke application programming interface (API)-garanties. De knooppuntenverzameling en de knooppuntattributen kunnen veranderen. Het serialisatieschema wordt onafhankelijk geversioneerd (AstDocument::CURRENT_SCHEMA_VERSION = '1.0.0'). De serializer detecteert en weigert een incompatibel schema, zodat opgeslagen AST-JSON een stabiel contract behoudt, ook wanneer de in-memory API verandert.

Terminal window
composer require nextpdf/core:^3

Hier representeert een AST de logische structuur van een document. Het is geen parser-syntaxboom voor één invoerformaat. AstDocument is de container. Die bevat het wortel-AstNode (dat NodeType::Document moet zijn), een schemaversie, een hash van het bron-Portable Document Format (PDF)-bestand en een paginatelling. Ongeldige constructie wordt geweigerd, waaronder een lege schemaversie, een paginatelling onder één of het verkeerde worteltype.

AstNode is het recursieve knooppunt. NodeType somt de semantische soorten op. Een knooppunt bevat onderliggende knooppunten, een optionele BoundingBox, optionele tekstinhoud en attributen die door NodeAttributeSchema worden gevalideerd. De knooppunt-API ondersteunt onveranderlijke afleiding. withBboxAndText() retourneert een nieuw knooppunt. deepClone() kopieert een subboom. NodeId is de value-object-identiteit. CitationAnchor koppelt een knooppunt aan een bronlocatie voor traceerbaarheid. AstNodeCollection is een Countable/IteratorAggregate-verzameling met ofType()-filtering.

AstSerializer is de persistentiegrens. serialize() schrijft een AstDocument naar JSON. deserialize() leest het weer in. Met canDeserialize() en extractSchemaVersion() kun je de compatibiliteit controleren voordat je parseert, zodat een schemamismatch een gedetecteerde conditie is in plaats van een corrupte payload. AstDocument::estimateTokenCount() helpt de inhoud te dimensioneren voor tokengebonden downstream-verwerking.

KlasseBelangrijkste ledenRol
AstDocumenttoJson(), nodeCount(), estimateTokenCount(), CURRENT_SCHEMA_VERSIONWortelcontainer; valideert worteltype en schema
AstNodeaddChild(), children(), childCount(), totalNodeCount(), withBboxAndText(), deepClone()Recursief semantisch knooppunt
NodeType (enum)Document, Heading, Table, Figure, FormField, …Semantische knooppuntsoort
AstNodeCollectionadd(), count(), isEmpty(), ofType(), toArray()Itereerbare, op type filterbare knooppuntenverzameling
AstSerializerserialize(), deserialize(), canDeserialize(), extractSchemaVersion()Geversioneerde JSON-persistentie
BoundingBoxtoArray(), equals()Value object voor geometrie (epsilonvergelijking)
NodeId / CitationAnchortoString(), equals(), toArray()Knooppuntidentiteit en anker voor brontraceerbaarheid
NodeAttributeSchemaattribuutvalidatieSchema voor knooppuntattributen

Voer composer docs:generate-api-php -- --module=Ast uit om de volledige PHPDoc-tabel te genereren.

Bouw een kleine boom en serialiseer die vervolgens.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Ast\AstNode;
use NextPDF\Ast\AstSerializer;
use NextPDF\Ast\NodeType;
$root = new AstNode(NodeType::Document);
$heading = new AstNode(NodeType::Heading);
$root->addChild($heading);
$root->addChild(new AstNode(NodeType::Paragraph));
echo "Nodes: {$root->totalNodeCount()}\n";
$json = (new AstSerializer())->serialize(/* an AstDocument wrapping $root */);

Voer defensief een roundtrip uit met een opgeslagen AST. Controleer de schemacompatibiliteit voordat je niet-vertrouwde JSON deserialiseert.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Ast\AstDocument;
use NextPDF\Ast\AstSerializer;
use Psr\Log\LoggerInterface;
final readonly class AstStore
{
public function __construct(
private AstSerializer $serializer,
private LoggerInterface $logger,
) {}
public function load(string $json): ?AstDocument
{
if (!$this->serializer->canDeserialize($json)) {
$this->logger->warning('AST JSON schema incompatible; rejected.', [
'found_schema' => $this->serializer->extractSchemaVersion($json),
'expected' => AstDocument::CURRENT_SCHEMA_VERSION,
]);
return null;
}
return $this->serializer->deserialize($json);
}
}
  • AstDocument vereist dat het wortelknooppunt NodeType::Document is. Een boom met een ander wortelknooppunt werpt bij constructie een uitzondering.
  • AstNode::withBboxAndText() en deepClone() retourneren nieuwe instanties. De beschikbare knooppuntmutators (addChild()) muteren het knooppunt. De afleidingshulpfuncties doen dat niet. Zorg dat je weet welke methode je aanroept.
  • Gebruik altijd canDeserialize() vóór deserialize() voor JSON uit een externe bron. Een mismatch in schemaversie is een detecteerbare, verwachte conditie.
  • estimateTokenCount() is een schatting voor het dimensioneren van downstream-verwerking, geen exacte tokenizertelling. Behandel het niet als gezaghebbend.
  • BoundingBox::equals() is een epsilonvergelijking (standaard 0.001). Exacte float-gelijkheid is niet het contract.

Het bouwen en doorlopen van de boom zijn O(n) in het aantal knooppunten. Serialisatie is lineair ten opzichte van de boomgrootte. Het reproduceerbaarheidsprofiel is bitwise. Dezelfde boom serialiseert naar dezelfde JSON-bytes, waardoor het schema als persistentiecontract stabiel blijft. De standaardreferentiewerklast blijft ruim binnen het budget van 1500 ms wall / 64 MB piek.

AstSerializer::deserialize() parseert JSON die mogelijk wordt opgeslagen of verzonden. Valideer eerst de compatibiliteit met canDeserialize(). Behandel de tekstinhoud en attributen van de gedeserialiseerde boom als niet-vertrouwde strings wanneer ze opnieuw de applicatie binnenkomen of worden weergegeven. De module zelf voert geen input/output (I/O) uit en bevat geen ingebedde externe data. Zie het dreigingsmodel van de engine in /modules/core/security/.

Deze module doet geen normatieve bewering over de PDF-specificatie. De semantische AST is een engine-interne abstractie. De module implementeert geen gestandaardiseerd documentmodel waarvan clausules moeten worden geciteerd. Waar de AST toegankelijkheidstagging voedt, worden de PDF/UA- en getagde-PDF-conformiteit van de uitvoer gedocumenteerd en gevalideerd op /modules/core/accessibility/ en /modules/core/conformance/, niet hier.