### Development Setup Commands Source: https://github.com/akankov/html-ast/blob/main/CONTRIBUTING.md Run these commands to set up the development environment and execute various checks. Tooling is managed via Docker images for reproducibility. ```bash make install ``` ```bash make test # PHPUnit on the default PHP_VERSION (8.4) ``` ```bash make test-all # PHPUnit on PHP 8.3, 8.4, 8.5 ``` ```bash make phpstan # PHPStan level max ``` ```bash make phan # Phan with ext-ast (builds the docker image first) ``` ```bash make cs-check # PHP-CS-Fixer dry-run ``` ```bash make rector-check # Rector dry-run ``` ```bash make ci # Full CI pipeline locally ``` -------------------------------- ### 30-Second Example: Parse, Traverse, and Print HTML Source: https://github.com/akankov/html-ast/blob/main/README.md This example demonstrates parsing an HTML string, traversing the resulting AST to remove 'data-testid' attributes using a visitor, and then printing the modified AST back to an HTML string. It utilizes the Parser, Visitor, NodeTraverser, and StandardPrinter classes. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Node\Element; use Akankov\HtmlAst\Visitor\Visitor; use Akankov\HtmlAst\Visitor\NodeTraverser; use Akankov\HtmlAst\Visitor\VisitorAction; use Akankov\HtmlAst\Printer\StandardPrinter; $result = Parser::detect()->parse($html); $stripTestIds = new class implements Visitor { public function enterNode(\Akankov\HtmlAst\Node\Node $n): VisitorAction|\Akankov\HtmlAst\Node\Node|null { if ($n instanceof Element && $n->hasAttribute('data-testid')) { return $n->withoutAttribute('data-testid'); } return null; } public function leaveNode(\Akankov\HtmlAst\Node\Node $n): VisitorAction|\Akankov\HtmlAst\Node\Node|null { return null; } }; $tree = (new NodeTraverser())->traverse($result->tree, [$stripTestIds]); $output = (new StandardPrinter())->print($tree); ``` -------------------------------- ### Install html-ast Package Source: https://github.com/akankov/html-ast/blob/main/README.md Use Composer to install the html-ast package. For PHP 8.3, an additional package is required. ```bash composer require akankov/html-ast ``` ```bash composer require masterminds/html5:^2.9 ``` -------------------------------- ### HTML AST Parser and Visitor Usage Source: https://github.com/akankov/html-ast/blob/main/PLAN.md A minimal usage example demonstrating how to parse HTML, traverse the resulting AST with a visitor, and print the tree. ```APIDOC ## Minimal usage example (sketch) ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Node\Element; use Akankov\HtmlAst\Visitor\Visitor; use Akankov\HtmlAst\Visitor\NodeTraverser; use Akankov\HtmlAst\Visitor\VisitorAction; use Akankov\HtmlAst\Printer\StandardPrinter; $result = Parser::detect()->parse($html); // ParseResult $visitor = new class implements Visitor { public function enterNode(\Akankov\HtmlAst\Node\Node $n): VisitorAction|\Akankov\HtmlAst\Node\Node|null { /* … */ } public function leaveNode(\Akankov\HtmlAst\Node\Node $n): VisitorAction|\Akankov\HtmlAst\Node\Node|null { /* … */ } }; $tree = (new NodeTraverser())->traverse($result->tree, [$visitor]); $output = (new StandardPrinter())->print($tree); ``` ``` -------------------------------- ### Minimal HTML AST Parsing and Traversal Example Source: https://github.com/akankov/html-ast/blob/main/PLAN.md Demonstrates the basic usage of the HTML AST library for parsing HTML, traversing the resulting tree with a visitor, and printing the output. Requires specific imports for Parser, Node, Visitor, and Printer components. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Node\Element; use Akankov\HtmlAst\Visitor\Visitor; use Akankov\HtmlAst\Visitor\NodeTraverser; use Akankov\HtmlAst\Visitor\VisitorAction; use Akankov\HtmlAst\Printer\StandardPrinter; $result = Parser::detect()->parse($html); // ParseResult $visitor = new class implements Visitor { public function enterNode(\Akankov\HtmlAst\Node\Node $n): VisitorAction|\Akankov\HtmlAst\Node\Node|null { /* … */ } public function leaveNode(\Akankov\HtmlAst\Node\Node $n): VisitorAction|\Akankov\HtmlAst\Node\Node|null { /* … */ } }; $tree = (new NodeTraverser())->traverse($result->tree, [$visitor]); $output = (new StandardPrinter())->print($tree); ``` -------------------------------- ### Configure Parse Options Source: https://context7.com/akankov/html-ast/llms.txt Utilize `ParseOptions` to control parsing behavior, including document vs. fragment mode and error handling (lenient vs. strict). This example shows creating options for full documents, strict parsing, fragment parsing, and fragment parsing with a custom context element. ```php use Akankov\HtmlAst\Parser\ParseOptions; use Akankov\HtmlAst\Parser\Parser; $parser = Parser::detect(); // Full document, lenient (default) $docOpts = ParseOptions::document(); // Full document, strict — throws on any parse error $strictOpts = ParseOptions::document()->strict(); // Fragment mode: parse as children of a context (default context) $fragOpts = ParseOptions::fragment(); // Fragment mode with a custom context element (e.g. inside a ) $tableFragOpts = ParseOptions::fragment('table'); $html = '

World & beyond

'; $fragHtml = ''; $docResult = $parser->parse($html, $docOpts); $fragResult = $parser->parse($fragHtml, $tableFragOpts); // Check quirks mode on full document use Akankov\HtmlAst\Node\QuirksMode; $quirks = $docResult->tree->quirksMode; // QuirksMode::NoQuirks | Quirks | LimitedQuirks // Fragment root carries its context element name echo $fragResult->tree->context; // "table" ``` -------------------------------- ### Get Byte-Offset Position Metadata with ByteRange Source: https://context7.com/akankov/html-ast/llms.txt Each Node includes a ByteRange object indicating its start and end byte offsets in the original source. Use SourceMap::lineColumn() to convert byte offsets to line and column numbers for diagnostics. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Position\{ByteRange, SourceMap}; use Akankov\HtmlAst\Node\Element; $html = "\n\n

Hello

\n"; $result = Parser::detect()->parse($html); // Navigate to the

element $p = $result->tree->children[0] // ->children[1] // (parser inserts it) ->children[0]; //

assert($p instanceof Element); assert($p->tagName === 'p'); $range = $p->range; echo $range->start; // e.g. 24 (byte offset of 'end; // e.g. 47 (byte offset just after '

') echo $range->length(); // 23 echo $range->contains(30); // true — byte 30 falls inside

...

// Slice the original source using the range $rawNode = substr($html, $range->start, $range->length()); echo $rawNode; // '

Hello

' // Convert byte offset to line/column $sourceMap = $result->sourceMap; ['line' => $line, 'column' => $col] = $sourceMap->lineColumn($range->start); echo "p element starts at line {"{$line}"}, column {"{$col}"}\n"; // Direct ByteRange construction (for synthetic nodes) $synthetic = new ByteRange(0, 0); // zero-length sentinel range for constructed nodes ``` -------------------------------- ### Get ByteRange Positions from ParseResult Source: https://context7.com/akankov/html-ast/llms.txt Access ByteRange positions on AST nodes obtained from ParseResult to map AST locations back to source coordinates using SourceMap::lineColumn(). This is crucial for diagnostic tooling. ```php use Html\SourceMap; // Assuming $node is an AST node with ByteRange information $byteRange = $node->byteRange(); $lineColumn = SourceMap::lineColumn($byteRange, $parseResult->sourceMap()); ``` -------------------------------- ### Dependency Injection with Contract Interfaces Source: https://context7.com/akankov/html-ast/llms.txt Demonstrates using stable contract interfaces for dependency injection in a minifier class. Requires importing contract interfaces and concrete implementations. ```php use Akankov\HtmlAst\Contract\{ParserContract, VisitorContract, PrinterContract}; use Akankov\HtmlAst\Parser\{Parser, ParseOptions, ParseResult}; use Akankov\HtmlAst\Node\Node; use Akankov\HtmlAst\Visitor\VisitorAction; use Akankov\HtmlAst\Printer\StandardPrinter; // ---- Dependency injection ---- class HtmlMinifier { public function __construct( private readonly ParserContract $parser, private readonly PrinterContract $printer, ) {} public function minify(string $html): string { $result = $this->parser->parse($html, ParseOptions::document()); // ... apply visitor transformations ... return $this->printer->print($result->tree); } } $minifier = new HtmlMinifier( parser: Parser::detect(), printer: new StandardPrinter(), ); echo $minifier->minify('

Hello

'); // ---- Test double implementing the stable contract ---- class StubParser implements ParserContract { public function __construct(private ParseResult $fixture) {} public function parse(string $html, ?ParseOptions $options = null): ParseResult { return $this->fixture; // return pre-built fixture in tests } } // ---- Custom visitor implementing VisitorContract ---- class AttributeSorter implements VisitorContract { public function enterNode(Node $n): Node|VisitorAction|null { if (!$n instanceof \Akankov\HtmlAst\Node\Element) { return null; } $sorted = $n->attributes; usort($sorted, fn($a, $b) => strcmp($a->name, $b->name)); return $n->withAttributes($sorted); } public function leaveNode(Node $n): Node|VisitorAction|null { return null; } } ``` -------------------------------- ### Parsing HTML and Traversing AST Source: https://context7.com/akankov/html-ast/llms.txt Demonstrates parsing an HTML string into an AST and manually traversing the node hierarchy. Shows how to access node properties, attributes, and perform immutable mutations like removing attributes or replacing children. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Node{ Document, DocumentFragment, Element, Attribute, Text, Comment, Doctype, CDataSection, NodeKind, AttributeQuoteStyle, QuirksMode }; $result = Parser::detect()->parse( '

Hello

' ); // Walk the tree manually $doc = $result->tree; // Document assert($doc->quirksMode === QuirksMode::NoQuirks); assert($doc->kind() === NodeKind::Document); // Recurse into children (html > body > p) foreach ($doc->children as $child) { if ($child instanceof Element && $child->tagName === 'html') { foreach ($child->children as $bodyOrHead) { if ($bodyOrHead instanceof Element && $bodyOrHead->tagName === 'body') { $p = $bodyOrHead->children[0]; //

assert($p instanceof Element); assert($p->tagName === 'p'); // Attributes preserve quoting style foreach ($p->attributes as $attr) { assert($attr instanceof Attribute); echo "{$attr->name}={$attr->value} ({$attr->quoteStyle->value})\n"; // class=main (double) // id=hero (single) } // Check attribute existence assert($p->hasAttribute('class') === true); $classAttr = $p->getAttribute('class'); // Attribute|null // Immutable mutation: remove an attribute, get a new Element $pWithoutId = $p->withoutAttribute('id'); assert(!$pWithoutId->hasAttribute('id')); assert($pWithoutId->hasAttribute('class')); // untouched // Replace children immutably $newText = new Text($p->range, 'New content'); $pWithNewChildren = $p->withChildren([$newText]); } } } } // ByteRange on every node $p = $doc->children[0]; // adjust to actual tree echo $p->range->start; // byte offset in original source echo $p->range->end; // exclusive end echo $p->range->length(); // end - start echo $p->range->contains(42); // bool — is byte 42 inside this node? ``` -------------------------------- ### Compose Visitors for HTML AST Transformation Source: https://context7.com/akankov/html-ast/llms.txt Demonstrates composing multiple visitors to strip data-testid attributes, remove HTML comments, and halt traversal at script tags. Visitors are run in order on each node. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Visitor\{Visitor, NodeTraverser, VisitorAction}; use Akankov\HtmlAst\Node\{Node, Element}; use Akankov\HtmlAst\Printer\StandardPrinter; // Visitor 1: strip all data-testid attributes $stripTestIds = new class implements Visitor { public function enterNode(Node $n): Node|VisitorAction|null { if ($n instanceof Element && $n->hasAttribute('data-testid')) { return $n->withoutAttribute('data-testid'); // replace with cleaned element } return null; // continue } public function leaveNode(Node $n): Node|VisitorAction|null { return null; } }; // Visitor 2: remove all HTML comments $removeComments = new class implements Visitor { public function enterNode(Node $n): Node|VisitorAction|null { if ($n instanceof \Akankov\HtmlAst\Node\Comment) { return VisitorAction::Remove; } return null; } public function leaveNode(Node $n): Node|VisitorAction|null { return null; } }; // Visitor 3: stop as soon as we find the first

world

'); $traverser = new NodeTraverser(); $transformed = $traverser->traverse($result->tree, [$skipScriptStyle, $uppercaseText]); //

text is uppercased; script content is untouched use Akankov\HtmlAst\Printer\StandardPrinter; echo (new StandardPrinter())->print($transformed); // Expected:

HELLO

WORLD

``` -------------------------------- ### Immutable Element Mutation with Wither Methods Source: https://context7.com/akankov/html-ast/llms.txt Illustrates how to use wither methods (`withoutAttribute`, `withAttributes`, `withChildren`) on `Element` nodes to create new instances with specific modifications. These methods are key for AST transformations. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Node{Element, Attribute, Text, AttributeQuoteStyle}; use Akankov\HtmlAst\Position\ByteRange; $result = Parser::detect()->parse('
Hi
'); $div = /* ... navigate to the div element ... */ $result->tree->children[0]->children[1]->children[0]; // withoutAttribute — remove a single attribute by name $divNoDataV = $div->withoutAttribute('data-v'); // $divNoDataV has only class="box" // withAttributes — replace the entire attribute list $newAttr = new Attribute( new ByteRange(0, 0), // synthetic range 'id', 'main', AttributeQuoteStyle::Double, ); $divWithNewAttrs = $div->withAttributes([$newAttr]); // $divWithNewAttrs has only id="main" // withChildren — replace child list $newSpan = new Element( new ByteRange(0, 0), 'span', [], [new Text(new ByteRange(0, 0), 'World')], ); $divWithNewChildren = $div->withChildren([$newSpan]); ``` -------------------------------- ### Document and Fragment Parsing Options Source: https://github.com/akankov/html-ast/blob/main/docs/design/api-v0.1.md Enables parsing of both full documents and HTML fragments. For fragments, specify the context element name for correct parsing. ```php ParseOptions::document() ParseOptions::fragment(string $context = 'body') ``` -------------------------------- ### Visitor API Method Signatures Source: https://github.com/akankov/html-ast/blob/main/docs/design/api-v0.1.md Defines the method signatures for the visitor pattern, allowing for node traversal and manipulation. Return null to continue traversal. ```php public function enterNode(Node $node): Node|VisitorAction|null; public function leaveNode(Node $node): Node|VisitorAction|null; ``` -------------------------------- ### HTML AST Library Structure Sketch Source: https://github.com/akankov/html-ast/blob/main/PLAN.md This sketch outlines the proposed directory structure and main components of the html-ast library, including Parser, Node, Token, Visitor, and Printer modules. ```plaintext Akankov\HtmlAst\ ├── Parser\ │ ├── Parser (interface) │ ├── NativeParser (\Dom\HTMLDocument backend, 8.4+) │ ├── MastermindsParser (masterminds/html5 backend, 8.3 fallback) │ ├── ParseOptions (mode: document|fragment, strict|lenient, …) │ └── ParseResult (tree, tokens, errors, sourceMap) ├── Node\ │ ├── Node (abstract base; readonly attributes; position ref) │ ├── Document │ ├── DocumentFragment │ ├── Element (tagName, attributes, children) │ ├── Attribute (name, value, quoteStyle, namespace) │ ├── Text │ ├── Comment │ ├── Doctype │ ├── ProcessingInstruction │ └── CDataSection (only inside foreign content) ├── Token\ │ ├── Token (kind, range, raw text) │ ├── TokenKind (enum: StartTag, EndTag, Text, Comment, Doctype, …) │ └── TokenStream ├── Position\ │ ├── ByteRange (start, end) │ └── SourceMap (offset → line/col on demand) ├── Visitor\ │ ├── Visitor (interface: enterNode, leaveNode) │ ├── NodeTraverser (drives traversal; handles REMOVE/STOP/REPLACE) │ └── VisitorAction (enum: Continue, SkipChildren, Stop, Remove, ReplaceWith) ├── Printer\ │ ├── Printer (interface) │ ├── StandardPrinter (normalized output; no trivia) │ └── LosslessPrinter (round-trips trivia, v0.2) ├── Contract │ ├── ParserContract │ ├── VisitorContract │ └── PrinterContract └── Internal ``` -------------------------------- ### Using Contract Interfaces for Dependency Injection Source: https://context7.com/akankov/html-ast/llms.txt The Contract namespace provides a stable API boundary for dependency injection, allowing swapping of parser backends or mocking in tests without coupling to concrete implementations. ```php use Html\Contract\ParserContract; // Example of type hinting for dependency injection function processHtml(ParserContract $parser, string $html): void { $parseResult = $parser->parse($html); // ... process AST ... } ``` -------------------------------- ### Parse HTML and Inspect Tokens Source: https://context7.com/akankov/html-ast/llms.txt Parses an HTML string into a token stream, allowing inspection of individual tokens and verification of round-trip fidelity. Requires importing various Token classes. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Token{ Token, TokenStream, TokenKind, StartTagToken, EndTagToken, CharacterToken, WhitespaceToken, CommentToken, DoctypeToken, CdataToken, EndOfFileToken, TokenAttribute }; use Akankov\HtmlAst\Position\ByteRange; $html = "

Hello & World

"; $result = Parser::detect()->parse($html); $stream = $result->tokens; echo $stream->count(); // number of tokens // Verify round-trip fidelity guarantee $reconstructed = implode('', array_map(fn(Token $t) => $t->raw, $stream->tokens)); assert($reconstructed === $html); // Inspect individual tokens foreach ($stream->tokens as $token) { match ($token->kind) { TokenKind::Doctype => printf("DOCTYPE raw=%s\n", var_export($token->raw, true)), TokenKind::Comment => printf("COMMENT data=%s\n", $token->data), // CommentToken TokenKind::StartTag => printf( "START <%s> selfClosing=%s attrs=%d\n", $token->tagName, $token->selfClosing ? 'true' : 'false', count($token->attributes), ), // StartTagToken TokenKind::EndTag => printf("END \n", $token->tagName), // EndTagToken TokenKind::Character => printf("CHAR data=%s\n", $token->data), // CharacterToken TokenKind::Whitespace => print("WHITESPACE\n"), // WhitespaceToken TokenKind::EndOfFile => print("EOF\n"), default => null, }; } // TokenAttribute: attributes on a StartTagToken preserve quoting style foreach ($stream->tokens as $token) { if ($token instanceof StartTagToken) { foreach ($token->attributes as $attr) { /** @var TokenAttribute $attr */ echo "{$attr->name}={$attr->value} quoted={$attr->quoteStyle->value}\n"; // class=hi quoted=single } } } // Slice tokens covering a specific byte range (e.g. a node's range) $pNode = $result->tree->children[0]->children[1]->children[0]; $pTokens = $stream->slice($pNode->range); // list fully inside

...

``` -------------------------------- ### Serialize AST to Normalized HTML with StandardPrinter Source: https://context7.com/akankov/html-ast/llms.txt Use StandardPrinter to convert an AST back into an HTML string. It enforces canonical attribute quoting, standard doctype, and HTML5 void element handling. For preserving original formatting, consider LosslessPrinter. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Printer\{Printer, StandardPrinter}; use Akankov\HtmlAst\Visitor\{Visitor, NodeTraverser, VisitorAction}; use Akankov\HtmlAst\Node\{Node, Element}; use Akankov\HtmlAst\Contract\PrinterContract; // StandardPrinter implements both Printer and PrinterContract $printer = new StandardPrinter(); // Parse → transform → print pipeline $html = "

"; $result = Parser::detect()->parse($html); // Strip the id attribute via a visitor $stripId = new class implements Visitor { public function enterNode(Node $n): Node|VisitorAction|null { if ($n instanceof Element && $n->hasAttribute('id')) { return $n->withoutAttribute('id'); } return null; } public function leaveNode(Node $n): Node|VisitorAction|null { return null; } }; $transformed = (new NodeTraverser())->traverse($result->tree, [$stripId]); $output = $printer->print($transformed); // StandardPrinter normalizes: // • tag names lowercased: DIV → div // • attributes double-quoted: CLASS='box' → class="box" // • void elements:

, // Expected output:

echo $output; // Printer is type-hintable via the stable contract interface function serializeSubtree(PrinterContract $p, Node $n): string { return $p->print($n); } echo serializeSubtree($printer, $result->tree); ``` -------------------------------- ### Accessing ParseResult Data Source: https://context7.com/akankov/html-ast/llms.txt Demonstrates how to access the AST tree, parse errors, token stream, and source map from the ParseResult object. This is useful for inspecting the parsed HTML structure and any encountered issues. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Parser\ParseErrorKind; use Akankov\HtmlAst\Node\Document; use Akankov\HtmlAst\Node\DocumentFragment; $parser = Parser::detect(); $result = $parser->parse('

Bold

'); // Access the AST root $root = $result->tree; // Document | DocumentFragment // Inspect parse errors (lenient mode: tree is always available) foreach ($result->errors as $error) { /** @var \Akankov\HtmlAst\Parser\ParseError $error */ echo sprintf( '[%s] %s at bytes %d–%d%s', $error->kind->value, // e.g. "tokenizer_error" $error->message, $error->range->start, $error->range->end, PHP_EOL, ); } // Access the token stream (for formatters / fidelity printers) echo $result->tokens->count(); // total token count // Verify round-trip fidelity: concatenating every token's ->raw equals the input $reconstructed = implode('', array_map(fn($t) => $t->raw, $result->tokens->tokens)); assert($reconstructed === '

Bold

'); // Access the source map for line/column lookup $sourceMap = $result->sourceMap; ['line' => $line, 'column' => $col] = $sourceMap->lineColumn(5); // offset 5 ``` -------------------------------- ### Parse HTML to AST with html-ast Source: https://context7.com/akankov/html-ast/llms.txt Use Parser::detect()->parse($html) to obtain a ParseResult containing the AST. This method is designed to be robust and handle various HTML inputs. ```php use Html ode\ParseResult; use Html\Parser; $html = '

Hello

'; $parseResult = Parser::detect()->parse($html); $ast = $parseResult->node(); ``` -------------------------------- ### Traverse and Transform HTML AST with Visitors Source: https://context7.com/akankov/html-ast/llms.txt Implement Visitor interfaces and use NodeTraverser::traverse() to modify the AST. Transformations can include replacing, removing, or skipping nodes, or stopping the traversal. ```php use Html\NodeTraverser; use Html\VisitorContract; class MyVisitor implements VisitorContract { // ... implementation ... } $traverser = new NodeTraverser(); $traverser->addVisitor(new MyVisitor()); $newAst = $traverser->traverse($ast); ``` -------------------------------- ### Print HTML AST back to String Source: https://context7.com/akankov/html-ast/llms.txt Use StandardPrinter::print() to serialize the transformed AST back into an HTML string. This is the final step in the parse-traverse-print pipeline. ```php use Html\Printer\StandardPrinter; $printer = new StandardPrinter(); $html = $printer->print($newAst); ``` -------------------------------- ### Lenient vs. Strict Parsing Options Source: https://github.com/akankov/html-ast/blob/main/docs/design/api-v0.1.md Configures the parser's error handling behavior. Use lenient mode for default HTML5 recovery, or strict mode to halt on the first error. ```php ParseOptions::document()->lenient(); // default ParseOptions::document()->strict(); // throws on first error ``` -------------------------------- ### ParseOptions Source: https://context7.com/akankov/html-ast/llms.txt Immutable value object for configuring parse mode (document or fragment) and error handling (lenient or strict). Factory methods allow for safe chaining of options. ```APIDOC ## `ParseOptions` — Configure parse mode and error handling Immutable value object controlling whether the parser runs in document or fragment mode and whether it recovers from errors (lenient, the default) or throws on the first error (strict). All factory methods return new instances, making chaining safe. ### Method ```php use Akankov\HtmlAst\Parser\ParseOptions; use Akankov\HtmlAst\Parser\Parser; $parser = Parser::detect(); // Full document, lenient (default) $docOpts = ParseOptions::document(); // Full document, strict — throws on any parse error $strictOpts = ParseOptions::document()->strict(); // Fragment mode: parse as children of a context (default context) $fragOpts = ParseOptions::fragment(); // Fragment mode with a custom context element (e.g. inside a
Cell
) $tableFragOpts = ParseOptions::fragment('table'); $html = '

World & beyond

'; $fragHtml = ''; $docResult = $parser->parse($html, $docOpts); $fragResult = $parser->parse($fragHtml, $tableFragOpts); // Check quirks mode on full document use Akankov\HtmlAst\Node\QuirksMode; $quirks = $docResult->tree->quirksMode; // QuirksMode::NoQuirks | Quirks | LimitedQuirks // Fragment root carries its context element name echo $fragResult->tree->context; // "table" ``` ``` -------------------------------- ### Handling Parse Errors with Match Source: https://context7.com/akankov/html-ast/llms.txt Shows how to iterate through parse errors and use a match expression to handle different `ParseErrorKind` values. This snippet also demonstrates extracting the problematic byte range from the source. ```php use Akankov\HtmlAst\Parser\Parser; use Akankov\HtmlAst\Parser\ParseError; use Akankov\HtmlAst\Parser\ParseErrorKind; $parser = Parser::detect(); $result = $parser->parse('

'); // malformed doctype foreach ($result->errors as $err) { match ($err->kind) { ParseErrorKind::TokenizerError => print "Tokenizer: {$err->message}\n", ParseErrorKind::TreeConstructionError => print "Tree: {$err->message}\n", ParseErrorKind::UnexpectedEndOfInput => print "Unexpected EOF\n", ParseErrorKind::Other => print "Other: {$err->message}\n", }; // Slice the original source to show the bad bytes $badBytes = substr($result->sourceMap->source, $err->range->start, $err->range->length()); echo " Bad input: " . var_export($badBytes, true) . "\n"; } ``` -------------------------------- ### Access Token Stream for Trivia Preservation Source: https://context7.com/akankov/html-ast/llms.txt The TokenStream on ParseResult::$tokens provides the trivia layer discarded by \Dom\HTMLDocument. Concatenating Token::$raw reconstructs the original input for exact transformations. ```php foreach ($parseResult->tokens() as $token) { // Process $token->raw, $token->type, etc. } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.
Cell