# Parserino: Fast HTML5 Parser and DOM Manipulation for D Parserino is a high-performance HTML5 parser and DOM manipulation library for the D programming language, written in pure D (no C dependencies; born as a D port of lexbor, from which the tree construction is derived). Names and behaviour follow the DOM, HTML and Selectors 4 standards. ## Core Concepts - **Document**: The main entry point for parsing and managing HTML content. - **Node**: Any node of the tree (element, text, comment, doctype, document, fragment). - **Element**: A node that is an element; it adds attributes, `innerHTML`, `matches`, ... It converts implicitly to `Node`; `node.asElement` goes back (invalid if the node isn't an element). - **Show**: Navigation methods take a template filter of node kinds (as DOM `whatToShow`): `children!(Show.All)`, `descendants!(Show.Comment)`, `firstChild!(Show.Text)`. The default is `Show.Element`, and then the result is an `Element`. - **Lazy Ranges**: Search and navigation ranges (`byTagName`, `bySelector`, `children`, `descendants`, ...) are lazy bidirectional struct ranges (`retro` gives reverse document order). - **Lazy Parsing**: `Document(html, Parsing.Lazy)` builds the tree only as far as the queries need (`doc.byClass("x").take(3)` stops early). Results are identical to a full parse. - **Errors**: searches and navigation return an invalid node (`== null`) or an empty range when nothing is found; invalid operations throw `ParserinoException`. - **Memory**: `Document` is reference counted; each `Node` keeps its document alive. Removed nodes stay valid. Getters return `string` copies; `...View` variants return slices of the document memory. ## Installation & Basic Usage Add `parserino` to your `dub.json` or `dub.sdl`. ```d import parserino; void main() { auto doc = Document("

Hello World!

"); assert(doc.body.firstChild.textContent == "Hello World!"); } ``` ## API Reference ### Document - `this(string html, Parsing parsing = Parsing.Eager, size_t chunkSize = DefaultChunkSize)`, `this(string html, ParseOptions options)`: Parse; `ParseOptions` has `parsing`, `chunkSize`, `scripting`. - `this(Snapshot)`, `snapshot`: A compact copy of the tree; `Document(snap)` rebuilds a document without parsing. - `ctDocument!html`: Parsed at compile time; each call returns a new document rebuilt from the stored tree. - `dup`: A deep copy. - `finishParsing()`, `isParsing`, `bytesParsed`: Control and inspect lazy parsing. - `documentElement`, `head`, `body` (the `` in frameset documents), `node` (the document as a `Node`). - `title`, `title(string)`: Get or set the document title. - `createElement(tag)` (an `Element`), `createText(text)`, `createComment(text)` (`Node`s). - `fragment(html, context = "body")`: Parses html in the context of an element into a `DocumentFragment` node; inserting it moves its children. - `toString()`: Serializes the entire document back to HTML; `toPrettyString()` indents it, to read it (whitespace changes: not for storing). - **Search Methods**: `byId(id)` (an invalid `Element` if not found), `byClass`, `byTagName` (`"*"` for all), `bySelector(css or Selector)`, `byComment(text)`, `byCommentExact(text)`, `children!show`, `descendants!show`. ### Node - `isValid`, `nodeType`, `nodeName`, `isElement`, `isText`, `isComment`, `asElement`, `ownerDocument`. - `textContent` (get/set), `dataView`. - Navigation (all with `!(Show...)`): `parent`, `firstChild`, `lastChild`, `nextSibling`, `previousSibling`, `children`, `descendants`; `walk!(show, descend)` (enter/leave steps, `descend(element)` false skips the children); `hasChildNodes`, `contains(node)` (inclusive). - Search: `byId`, `byClass`, `byTagName`, `bySelector`, `byComment`, `byCommentExact`. - Mutations: `append`, `prepend`, `before`, `after`, `replaceWith` (accept a `Node`, a `string` as text, `"x".asFragment` as html, a fragment), `appendChild(node)`, `remove()`, `~=`. - `dup`, `shallowDup`, `toString`, `toPrettyString`. ### Element (also has all the `Node` members) - `localName` ("div", "foreignObject"), `tagName` ("DIV"), `id` (get/set), `classes`, `attributes`. - `getAttribute(name)` (`null` if missing), `setAttribute`, `hasAttribute`, `removeAttribute`. - Views: `localNameView`, `idView`, `getAttributeView`, `classesView`, `attributesView`. - `innerHTML`, `outerHTML` (get/set), `innerText` (same as `textContent`), `startTag`. - `matches(css)`, `isEmpty` (`:empty`), `isBlank` (`:blank`), `copyFrom(e)`, `shallowCopyFrom(e)`. - `el = "html";` replaces the element with the parsed one. ### Parse errors and encodings - `ParseOptions.collectErrors` and `doc.parseErrors`: a list of `ParseError` (`code`, `line`, `column`, `name` as in the HTML standard, e.g. "unexpected-null-character"). With `ctDocument!(html, options)` the errors are compile errors. - The input is UTF-8 (BOM removed, invalid bytes become U+FFFD). `parserino.encoding.toUtf8(bytes)` detects the encoding (BOM, ``) and converts UTF-16, windows-1252, ISO-8859-2, windows-1250/1251. ### Selector - `Selector(string css)`: A compiled css selector, reusable with any document (throws `ParserinoException` on invalid syntax). `ctSelector!css` and `bySelector!css` compile it at compile time. `isValidSelector(css)` checks the syntax without throwing. ### Range Helpers - `frontOrThrow(range)`: The first element; throws `ParserinoException` if the range is empty. - `frontOr(range, fallback)`: The first element or `fallback`. - `frontOrInit(range)`: The first element or an invalid node. ### Fragment Handling To insert raw HTML strings as DOM nodes (instead of plain text), use `.asFragment`: ```d doc.body.append("

New Paragraph

".asFragment); ``` ## Examples Explore the `examples/` directory for practical implementations: - `01_hello_world`: Basic parsing and editing. - `02_search_elements`: Using `byTagName` and CSS selectors. - `03_edit_dom`: Adding fragments and creating new elements. - `04_dlang_scraper`: Real-world scraping with lazy parsing and CSS selectors: what's new in the latest D, from dlang.org. - `05_html_templates`: Parserino as a template engine with serverino: plain html templates (parsed at compile time with `ctDocument`) filled by id/class, cloned rows, removed sections, automatic escaping; two different layouts filled by the same code.