콘텐츠로 이동

Ast: 시맨틱 문서 트리와 직렬화

Ast 모듈은 엔진의 시맨틱 문서 트리입니다. 이 모듈은 문서를 타입이 지정된 노드 계층으로 모델링하며 — Document, Section, Heading, Paragraph, List, Table, Figure, Code, FormField — 경계 상자, 인용 앵커, 버전이 지정된 JSON 직렬화를 제공합니다. 접근성 태깅 계층은 이를 사용해 구조 트리를 생성합니다.

안정성: 실험적(experimental). 이것은 내부 모델 표면입니다. 이 클래스들은 버전이 고정된 공개 API 보장을 제공하지 않으며, 노드 집합과 노드 속성은 진화합니다. 직렬화 스키마는 독립적으로 버전이 지정됩니다 (AstDocument::CURRENT_SCHEMA_VERSION = '1.0.0'). 직렬화기는 호환되지 않는 스키마를 감지하고 거부할 수 있으므로, 영구 저장된 AST JSON은 안정적인 계약을 가지며, 인메모리 API가 그렇지 않더라도 이 계약은 유지됩니다.

Terminal window
composer require nextpdf/core:^3

여기서 AST는 문서의 논리 구조를 나타내는 시맨틱 추상화이며, 특정 입력 형식용 파서 구문 트리가 아닙니다. AstDocument은(는) 컨테이너입니다. 루트 AstNode(반드시 NodeType::Document이어야 함), 스키마 버전, 소스 PDF 해시, 페이지 수를 보유합니다. 유효하지 않은 생성(빈 스키마 버전, 1 미만의 페이지 수, 잘못된 루트 타입)은 거부합니다.

AstNode은(는) 재귀 노드입니다. NodeType은(는) 시맨틱 종류를 열거합니다. 노드는 자식 노드, 선택적 BoundingBox, 선택적 텍스트 콘텐츠, 그리고 NodeAttributeSchema을(를) 통해 스키마로 검증된 속성을 담습니다. 노드 API는 불변 파생을 위해 설계되었습니다. withBboxAndText()은(는) 새 노드를 반환합니다. deepClone()은(는) 하위 트리를 복사합니다. NodeId은(는) 값 객체 식별자입니다. CitationAnchor은(는) 추적성을 위해 노드를 소스 위치에 연결합니다. AstNodeCollection은(는) ofType() 필터링을 지원하는 Countable/IteratorAggregate 집합입니다.

AstSerializer은(는) 영속성 경계입니다. serialize()은(는) AstDocument을(를) JSON으로 씁니다. deserialize()은(는) 이를 다시 읽습니다. canDeserialize()extractSchemaVersion()을(를) 사용하면 소비자가 파싱 전에 호환성을 확인할 수 있으므로, 스키마 불일치는 손상된 로드가 아니라 감지 가능한 조건이 됩니다. AstDocument::estimateTokenCount()이(가) 존재하는 이유는 이 트리가 다운스트림의 토큰 제한 처리를 위해 콘텐츠 크기를 산정하는 데에도 사용되기 때문입니다.

클래스주요 멤버역할
AstDocumenttoJson(), nodeCount(), estimateTokenCount(), CURRENT_SCHEMA_VERSION루트 컨테이너; 루트 타입과 스키마를 검증합니다
AstNodeaddChild(), children(), childCount(), totalNodeCount(), withBboxAndText(), deepClone()재귀 시맨틱 노드
NodeType (enum)Document, Heading, Table, Figure, FormField, …시맨틱 노드 종류
AstNodeCollectionadd(), count(), isEmpty(), ofType(), toArray()반복 가능하며 타입별 필터링을 지원하는 노드 집합
AstSerializerserialize(), deserialize(), canDeserialize(), extractSchemaVersion()버전이 지정된 JSON 영속성
BoundingBoxtoArray(), equals()기하 값 객체(엡실론 비교)
NodeId / CitationAnchortoString(), equals(), toArray()노드 식별자 및 소스 추적성 앵커
NodeAttributeSchema속성 검증노드 속성을 위한 스키마

전체 PHPDoc 표를 보려면 composer docs:generate-api-php -- --module=Ast을(를) 실행하세요.

작은 트리를 만들고 직렬화합니다.

<?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 */);

신뢰할 수 없는 JSON을 역직렬화하기 전에 스키마 호환성을 확인하면서, 영구 저장된 AST를 방어적으로 왕복 변환합니다.

<?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은(는) 루트 노드가 NodeType::Document일 것을 요구합니다. 다른 루트를 가진 트리는 생성 시 예외를 던집니다.
  • AstNode::withBboxAndText()deepClone()은(는) 새 인스턴스를 반환합니다. 기존 노드 변경자(addChild())는 변경을 수행합니다. 파생 헬퍼는 변경하지 않습니다. 어느 쪽을 호출하는지 유의하세요.
  • 외부에서 받은 JSON은 항상 canDeserialize()(으)로 deserialize()을(를) 가드하세요. 스키마 버전 불일치는 감지 가능하며 예상된 조건입니다.
  • estimateTokenCount()은(는) 다운스트림 처리 크기를 산정하기 위한 추정치이며, 정확한 토크나이저 카운트가 아닙니다. 이를 권위 있는 값으로 취급하지 마세요.
  • BoundingBox::equals()은(는) 엡실론 비교입니다(기본값 0.001). 정확한 부동소수점 동등성은 계약이 아닙니다.

트리 생성과 순회는 노드 수에 대해 O(n)입니다. 직렬화는 트리 크기에 선형적입니다. 재현성 프로필은 bitwise입니다. 동일한 트리는 동일한 JSON 바이트로 직렬화되며, 이것이 스키마를 안정적인 영속성 계약으로 만드는 요소입니다. 기본 참조 워크로드는 1500 ms 벽시계 / 64 MB 최대 예산 안에 충분히 들어갑니다.

AstSerializer::deserialize()은(는) 영구 저장되거나 전송될 수 있는 JSON을 파싱합니다. 먼저 canDeserialize()(으)로 호환성을 검증하세요. 역직렬화된 트리의 텍스트 콘텐츠와 속성이 애플리케이션에 다시 진입하거나 렌더링될 때는 신뢰할 수 없는 문자열로 취급하세요. 모듈 자체는 어떠한 I/O도 수행하지 않으며 외부 데이터를 포함하지 않습니다. /modules/core/security/에서 엔진 위협 모델을 참고하세요.

이 모듈은 어떠한 PDF 사양에 대해서도 규범적 주장을 하지 않습니다. 시맨틱 AST는 엔진 내부 추상화입니다. 이는 조항을 인용해야 하는 표준화된 문서 모델을 구현하지 않습니다. AST가 접근성 태깅에 공급되는 경우, 출력물의 PDF/UA 및 태그된 PDF 적합성은 여기가 아니라 /modules/core/accessibility//modules/core/conformance/에서 문서화되고 검증됩니다.