##################################
Transforming without a full tree
##################################
Not every job needs a navigable tree. Sometimes you want to change markup as it streams, reshape one document into
another, or check a document against a contract. This tutorial runs a streaming rewrite, an XSLT transform, and a schema
validation -- three transforms that never ask you to walk a tree by hand.
***********************
Rewrite as it streams
***********************
:func:`turbohtml.rewrite.rewrite` transforms a document in one pass that never builds a tree, the way Cloudflare's
lol-html rewrites at the edge. Register a ``(selector, handler)`` pair; the handler receives each match and edits it,
while everything you do not touch is copied through. Here every image gets ``loading="lazy"``:
.. testcode::
from turbohtml.rewrite import rewrite
def lazy(img):
img.set_attribute("loading", "lazy")
print(rewrite("
", elements=[("img", lazy)]))
.. testoutput::

Because the rewriter never looks ahead, only selectors decidable from an element and its ancestors match;
:doc:`/how-to/rewriting` lists which, and :doc:`/explanation/streaming` explains why.
*********************
Transform with XSLT
*********************
To reshape one document into another, apply an XSLT 1.0 stylesheet, the job lxml's ``etree.XSLT`` does. Parse the
stylesheet with :func:`turbohtml.parse_xml`, wrap it in :class:`turbohtml.transform.Transform`, and call it on a source:
.. testcode::
from turbohtml import parse_xml
from turbohtml.transform import Transform
style = parse_xml(
''
'
")))
.. testoutput::