Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/turbohtml/transform.py: 89%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2turbohtml.transform: XSLT 1.0 transformation, the job ``lxml.etree.XSLT`` does.
4Parse an XSLT stylesheet as XML with :func:`turbohtml.parse_xml`; use any parsed tree as the source document.
5:class:`Transform` compiles the stylesheet and applies it to a source, mirroring lxml's compile-once, apply-many shape::
7 from turbohtml import parse_xml
8 from turbohtml.transform import Transform
10 style = parse_xml(stylesheet_source)
11 convert = Transform(style)
12 result = convert(parse_xml(document_source))
14The whole transform runs in the C extension, reusing turbohtml's XPath 1.0 engine for every match pattern and select
15expression. It covers XSLT 1.0: ``xsl:template`` (match, name, mode, priority), ``xsl:apply-templates``,
16``xsl:call-template``, ``xsl:for-each``, ``xsl:if``, ``xsl:choose``, ``xsl:value-of``, ``xsl:copy``/``xsl:copy-of``,
17``xsl:element``/``xsl:attribute``/``xsl:text``, ``xsl:variable``/``xsl:param``, ``xsl:sort``, multi-level
18``xsl:number``, ``xsl:key`` and the ``key()`` function, ``xsl:strip-space``/``xsl:preserve-space``,
19``xsl:attribute-set``, ``xsl:namespace-alias``, ``xsl:import`` with import precedence, ``xsl:fallback``, simplified
20stylesheets, ``cdata-section-elements`` and the ``xml``/``html``/``text`` output methods (html is auto-selected for a
21null-namespace ``html`` document element). The documented boundaries are locale-aware ``xsl:sort`` collation (a locale
22layer turbohtml does not carry) and ``id()`` over DTD-declared IDs (no DTD layer).
24``base_url`` supplies the stylesheet path or file URL used to resolve each ``xsl:import``. Disable imports for an
25untrusted stylesheet, or constrain them to ``import_root``. The libxslt XSLT 1.0 Recommendation test corpus covers the
26processor (see ``tests/conformance/test_xslt_conformance.py``).
27"""
29from __future__ import annotations
31from typing import TYPE_CHECKING
33from ._html import _xpath_literal, _xslt_compile, _xslt_resolve_imports, _xslt_transform
35if TYPE_CHECKING:
36 from pathlib import Path
38 from ._html import Node
40__all__ = ["Transform", "strparam", "transform"]
43class Transform:
44 """
45 A compiled XSLT 1.0 stylesheet, callable over source documents (lxml's ``etree.XSLT``).
47 :param stylesheet: the stylesheet, a tree parsed with :func:`turbohtml.parse_xml`.
48 :param base_url: the stylesheet's path or file URL, against which ``xsl:import`` hrefs resolve; required only when
49 the stylesheet imports.
50 :param allow_imports: set to :data:`False` when a stylesheet must not read other files.
51 :param import_root: when set, imported files must resolve inside this directory, including through nested imports.
52 """
54 __slots__ = ("_compiled",)
56 def __init__(
57 self,
58 stylesheet: Node,
59 *,
60 base_url: str | None = None,
61 allow_imports: bool = True,
62 import_root: str | Path | None = None,
63 ) -> None:
64 """Compile an immutable stylesheet snapshot."""
65 self._compiled = _xslt_compile(
66 stylesheet,
67 _xslt_resolve_imports(stylesheet, base_url, allow_imports, import_root),
68 )
70 def __call__(self, source: Node, /, **params: str) -> str:
71 """
72 Transform a source document and return the serialized result.
74 :param source: the document to transform, a parsed tree.
75 :param params: top-level ``xsl:param`` values, each an XPath expression string; wrap a plain string in
76 :func:`strparam` (``convert(doc, title=strparam(title))``) so its quotes cannot end the literal.
77 :raises ValueError: if the stylesheet or an expression is malformed, a referenced key or named template is
78 undeclared, or the html output method would write a processing instruction that holds ``>``.
79 :raises RuntimeError: on an ``xsl:message`` with ``terminate="yes"``.
80 :returns: the transformed document serialized under the stylesheet's ``xsl:output`` method.
81 """
82 return _xslt_transform(self._compiled, source, params or None)
85def transform(
86 stylesheet: Node,
87 source: Node,
88 /,
89 *,
90 base_url: str | None = None,
91 allow_imports: bool = True,
92 import_root: str | Path | None = None,
93 **params: str,
94) -> str:
95 """
96 Apply an XSLT 1.0 stylesheet to a source document in one call.
98 Equivalent to constructing and calling :class:`Transform`; retain a :class:`Transform` when one stylesheet applies
99 to many documents so it is compiled once.
101 :param stylesheet: the stylesheet, a tree parsed with :func:`turbohtml.parse_xml`.
102 :param source: the document to transform, a parsed tree.
103 :param base_url: the stylesheet's path or file URL, against which ``xsl:import`` hrefs resolve; required only when
104 the stylesheet imports.
105 :param allow_imports: set to :data:`False` when a stylesheet must not read other files.
106 :param import_root: when set, imported files must resolve inside this directory, including through nested imports.
107 :param params: top-level ``xsl:param`` values, each an XPath expression string; pass text through
108 :func:`strparam`.
109 :returns: the transformed document serialized under the stylesheet's ``xsl:output`` method.
110 """
111 return Transform(
112 stylesheet,
113 base_url=base_url,
114 allow_imports=allow_imports,
115 import_root=import_root,
116 )(source, **params)
119def strparam(value: str, /) -> str:
120 """
121 Quote a string as an XPath string literal, for passing text as an ``xsl:param`` value.
123 A parameter value is an XPath expression, so an unquoted or hand-quoted string that holds a quote runs as a query
124 over the source document. The literal this returns reads back as ``value`` whatever quotes it holds.
126 :param value: the text the stylesheet should receive.
127 :raises TypeError: if ``value`` is not a str.
128 :returns: an XPath expression that evaluates to ``value``.
129 """
130 return _xpath_literal(value)