################### Traversal objects ################### turbohtml already walks a tree two ways: the lazy :attr:`~turbohtml.Node.descendants` iterator visits every node once in document order, and the query methods (:meth:`~turbohtml.Node.find_all`, :meth:`~turbohtml.Node.select`) return a materialized list. :class:`~turbohtml.TreeWalker` and :class:`~turbohtml.NodeIterator` fill the gap between them: a *steerable, filtered* view. They are the DOM Living Standard traversal objects, so code ported from a browser or from `jsdom `_ keeps its traversal logic (see :doc:`/migration/jsdom`). The two differ in shape. A :class:`~turbohtml.TreeWalker` is a cursor: it remembers a :attr:`~turbohtml.TreeWalker.current_node` and moves relative to it -- to a child, a sibling, the parent, or the next or previous node in document order -- so you can change direction mid-walk, the way an outline editor moves through headings. A :class:`~turbohtml.NodeIterator` is a flat sequence: it yields the accepted nodes front to back (or back to front), with no notion of depth. Both are confined to a ``root`` subtree and both apply the same filter. ***************** Reject vs. skip ***************** Filtering has two stages, run in this order for every node the walk reaches. First the ``what_to_show`` bitmask: a node whose DOM type is not in the mask is dropped without the callback ever seeing it. Then, if the type passes, the ``filter`` callback returns one of three verdicts. Two of them keep the walk going but mean different things, and the difference is the reason a *tree* walker exists: - :attr:`~turbohtml.NodeFilter.FILTER_ACCEPT` yields the node. - :attr:`~turbohtml.NodeFilter.FILTER_SKIP` drops the node but keeps descending, so an unwanted wrapper vanishes while its contents stay reachable. - :attr:`~turbohtml.NodeFilter.FILTER_REJECT` drops the node *and its whole subtree*, so a rejected ``