Documentation
¶
Overview ¶
Package xslt implements XSLT 2.0 transformation over the xdm data model, using the xpath package for expression evaluation.
Index ¶
Constants ¶
const DefaultMaxDepth = 1000
DefaultMaxDepth bounds template recursion when TransformOptions.MaxDepth is zero. It matches xdm.DefaultMaxDepth so that a document the parser accepts is one an identity transform can copy: the recursion counted here is the ordinary descent through the tree, not only a stylesheet calling itself.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CompileOptions ¶
type CompileOptions struct {
// Resolver loads xsl:include and xsl:import targets. Nil disables them,
// which is the safe default for untrusted stylesheets.
Resolver ModuleResolver
// BaseURI of the stylesheet, for resolving relative include paths.
BaseURI string
// StaticParams supplies values for top-level xsl:param at compile time.
StaticParams map[string]string
// SchemaResolver loads the schemas named by xsl:import-schema. Nil
// disables loading by location, for the same reason a nil Resolver
// disables xsl:include: following a location means fetching whatever
// the stylesheet names. An inline <xs:schema> child needs no resolver.
SchemaResolver xsd.Resolver
}
CompileOptions configures compilation.
type DecimalFormat ¶
type DecimalFormat struct {
Name xdm.QName
DecimalSeparator rune
GroupingSeparator rune
Percent rune
PerMille rune
ZeroDigit rune
Digit rune
PatternSeparator rune
MinusSign rune
Infinity string
NaN string
}
DecimalFormat holds an xsl:decimal-format declaration.
Every symbol is configurable because the instruction exists to serve locales: a German invoice writes 1.234,56 where an English one writes 1,234.56, and the picture string is written once against whatever symbols the format declares.
type FileResolver ¶
type FileResolver struct {
// Roots are the directories a relative or absolute path may resolve
// inside. A path escaping all of them is refused.
Roots []string
// contains filtered or unexported fields
}
FileResolver loads stylesheet modules and documents from the filesystem, confined to a set of allowed directories.
The confinement is the point. A stylesheet that can call document() on any path is a file-disclosure primitive, and one that can reach http:// is an SSRF primitive — but a blanket deny is not workable either, because real rule sets load code lists that ship beside the stylesheet. Naming the directories makes the trust boundary explicit and auditable.
func NewFileResolver ¶
func NewFileResolver(roots ...string) (*FileResolver, error)
NewFileResolver returns a resolver confined to the given directories.
func (*FileResolver) ResolveDocument ¶
func (r *FileResolver) ResolveDocument(uri, base string) (*xdm.Tree, error)
ResolveDocument implements xpath.DocumentResolver for fn:doc and fn:document.
func (*FileResolver) ResolveModule ¶
ResolveModule implements ModuleResolver for xsl:include and xsl:import.
type Instruction ¶
type Instruction interface {
// Execute runs the instruction, appending to out.
Execute(rt *runtime, out *outputBuilder) error
}
Instruction is one compiled XSLT instruction.
Instructions write to an output builder rather than returning values, because an XSLT sequence constructor produces a *stream* of nodes and atomic values: xsl:element opens a node that subsequent instructions add children to. Returning trees from each instruction and concatenating them would mean building and copying the same subtree repeatedly.
type ModuleResolver ¶
ModuleResolver loads an included or imported stylesheet module.
type OutputSettings ¶
type OutputSettings struct {
Method string // "xml", "html", "text"
Indent bool
OmitXMLDecl bool
Encoding string
DocTypePublic string
DocTypeSystem string
CDataElements []xdm.QName
Standalone string
// Version is xsl:output/@version; "5.0" selects the HTML5 doctype.
Version string
// UseCharacterMaps names the xsl:character-map declarations applied at
// serialisation.
UseCharacterMaps []xdm.QName
}
OutputSettings holds the xsl:output declaration.
type Pattern ¶
type Pattern struct {
// contains filtered or unexported fields
}
Pattern is a compiled xsl:template match pattern.
Patterns look like path expressions but mean something different: a path says "navigate from here", a pattern says "does this node match". The natural implementation of matching — evaluate the path and check membership — is quadratic, because it would visit every node in the document for every node being matched.
Instead a pattern is matched right-to-left from the candidate node: check the last step's node test against the node itself, then walk *up* verifying each preceding step. That makes a match cost O(depth) rather than O(document size), which is the difference between a transform that finishes and one that does not on a large invoice.
func CompilePattern ¶
func CompilePattern(src string, ns xpath.NamespaceResolver) (*Pattern, error)
CompilePattern compiles an XSLT match pattern.
func (*Pattern) Matches ¶
Matches reports whether node matches the pattern.
ctx supplies the focus for predicate evaluation. Predicates in a pattern are evaluated with the candidate node as the context item, and with a context position derived from its position among its like-named siblings — which is why "para[1]" as a pattern means "a para that is the first para child of its parent" rather than "the first para in the document".
func (*Pattern) Priority ¶
Priority returns the pattern's default priority, per the XSLT rules: a specific name test scores 0, a namespace wildcard -0.25, a full wildcard or bare kind test -0.5, and anything more complex 0.5.
These numbers exist so that a more specific template wins over a general one without the author having to say so. Getting them wrong makes template selection silently pick the wrong rule, which is far harder to debug than a crash.
type Result ¶
type Result struct {
// Nodes is the result sequence, which for a typical stylesheet is a
// single element.
Nodes xdm.Sequence
// Messages holds xsl:message output, in the order produced.
Messages []string
// Secondary holds the documents produced by xsl:result-document, in the
// order produced. It is empty for the great majority of stylesheets,
// which produce a single result.
Secondary []SecondaryResult
// contains filtered or unexported fields
}
Result is the outcome of a transform.
func (*Result) Serialize ¶
Serialize writes the result using the stylesheet's xsl:output settings.
Deliberately not named WriteTo: that name implies io.WriterTo, whose contract returns a byte count this would have to fabricate.
type SecondaryResult ¶
type SecondaryResult struct {
// Href is the resolved @href value, as written by the stylesheet. It is
// the caller's choice what to do with it — this engine never writes to
// the filesystem on a stylesheet's behalf, since a transform that can
// create files anywhere the process can write is a hazard the caller
// should be the one to opt into.
Href string
// Nodes is the result sequence for this document.
Nodes xdm.Sequence
// Output holds the serialisation settings that apply to this document,
// taken from @format and any serialisation attributes on the instruction.
Output OutputSettings
}
SecondaryResult is one document produced by xsl:result-document.
It is kept separate from the principal result rather than merged into it: the whole point of the instruction is that the stylesheet author wants two distinct documents, and folding them together would give a caller expecting several outputs a single plausible-looking wrong one.
func (*SecondaryResult) Serialize ¶
Serialize writes the secondary document using its own output settings.
A caller holding a SecondaryResult would otherwise have no way to render it: the serialiser is unexported, and re-deriving these settings from the stylesheet is exactly the duplication @format exists to avoid.
func (*SecondaryResult) String ¶
func (sr *SecondaryResult) String() string
String renders the secondary document using its own output settings.
type Stylesheet ¶
type Stylesheet struct {
// contains filtered or unexported fields
}
Stylesheet is a compiled XSLT 2.0 stylesheet.
Compilation is separated from execution so that a stylesheet compiles once and transforms many documents concurrently. Everything reachable from here is immutable after Compile returns; all per-transform state lives in the runtime context. That is what makes a compiled EN 16931 rule set — tens of megabytes — shareable rather than per-worker.
func Compile ¶
func Compile(doc *xdm.Node, opts CompileOptions) (*Stylesheet, error)
Compile compiles a stylesheet from a parsed XSLT document.
func (*Stylesheet) Output ¶
func (s *Stylesheet) Output() OutputSettings
Output returns the stylesheet's output settings.
func (*Stylesheet) Schema ¶
func (s *Stylesheet) Schema() *xsd.Schema
Schema returns the schema assembled from the stylesheet's xsl:import-schema declarations, or nil when it has none.
It is exposed so that a caller can validate a source document against the same schema the stylesheet declares, rather than having to load it twice and risk the two disagreeing.
func (*Stylesheet) Transform ¶
func (s *Stylesheet) Transform(ctx context.Context, source *xdm.Node, opts TransformOptions) (*Result, error)
Transform applies the stylesheet to a source document.
The Stylesheet is not mutated, so one compiled stylesheet may be used from many goroutines concurrently.
type Template ¶
type Template struct {
Match *Pattern
Name xdm.QName
HasName bool
Mode []string // empty means the default (unnamed) mode
Priority float64
Params []*Variable
Body []Instruction
// contains filtered or unexported fields
}
Template is a compiled xsl:template.
type TransformOptions ¶
type TransformOptions struct {
// Params supplies values for top-level xsl:param, keyed by Clark name
// ("{uri}local", or just "local" for a no-namespace parameter).
Params map[string]xdm.Sequence
// Documents resolves fn:doc and fn:document. Nil disables them, which is
// the default: a stylesheet that can open arbitrary URIs is an SSRF and
// file-disclosure vector, and validation rule sets need at most the code
// lists shipped beside them.
Documents xpath.DocumentResolver
// Collections resolves fn:collection. Nil disables it, which is the
// default, and setting Documents does not set this: enabling fn:doc for
// a known code list should not also let a stylesheet enumerate whatever
// a collection URI happens to name.
Collections xpath.CollectionResolver
// MaxDepth bounds template recursion. Zero means DefaultMaxDepth; a
// negative value means no limit.
//
// The bound catches a stylesheet that recurses without a base case,
// which is the common authoring mistake. But it also counts the ordinary
// descent of an identity transform, so a limit below the parser's left
// this refusing documents it had just accepted: at the old fixed 300, a
// legal 500-deep document could be parsed and not transformed.
MaxDepth int
// InitialMode names the mode for the initial apply-templates.
InitialMode string
// InitialTemplate names a template to invoke instead of matching the
// document root, which is how a stylesheet with only named templates is
// entered.
InitialTemplate string
// Now fixes the value fn:current-dateTime returns. Leave it zero to use
// the wall clock; set it to make a transform reproducible, which is what
// a golden-file test needs.
Now time.Time
// ImplicitTimezone is the offset in minutes for date values with no
// timezone. Defaults to UTC so that results are reproducible across
// machines.
ImplicitTimezone int
}
TransformOptions configures one transform.
type Variable ¶
type Variable struct {
Name xdm.QName
// Select is the value expression, or nil when the value comes from the
// element's content.
Select *xpath.Compiled
// Body is the sequence constructor used when Select is absent. A variable
// with content builds a temporary tree, which is why the two forms are
// not interchangeable: "select" yields whatever the expression yields,
// while content always yields a document node.
Body []Instruction
// Required marks a parameter that must be supplied.
Required bool
// Tunnel marks a tunnel parameter, which passes through templates that do
// not declare it.
Tunnel bool
// AsType is the compiled "as" declaration, applied to the value when
// present. XSLT converts the value to this type rather than merely
// checking it, so it changes results and not just error messages.
AsType *sequenceType
}
Variable is a compiled xsl:variable, xsl:param or xsl:with-param.