Documentation
¶
Overview ¶
Package xslt implements XSLT 2.0 transformation over the xdm data model, using the xpath package for expression evaluation.
Index ¶
- Constants
- func ApplyParameterDocument(root *xdm.Node, o *OutputSettings) error
- func Serialize(w io.Writer, seq xdm.Sequence, opts OutputSettings, charMap map[rune]string) error
- func SerializeAsXML(r *Result) string
- func SetSerializationParam(o *OutputSettings, name, val string) error
- type CompileOptions
- type DecimalFormat
- type FileResolver
- func (r *FileResolver) Preload(uri string, tree *xdm.Tree)
- func (r *FileResolver) ResolveDocument(uri, base string) (*xdm.Tree, error)
- func (r *FileResolver) ResolveEntity(systemID, publicID, base string) (io.ReadCloser, string, error)
- func (r *FileResolver) ResolveModule(href, base string) (*xdm.Node, string, error)
- func (r *FileResolver) ResolveText(uri, base, encoding string) (string, error)
- type Instruction
- type ModuleResolver
- type OutputSettings
- type PackageResolver
- type Pattern
- type Result
- type SecondaryResult
- type Stylesheet
- type Template
- type TransformOptions
- type Variable
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 ¶
func ApplyParameterDocument ¶ added in v1.2.0
func ApplyParameterDocument(root *xdm.Node, o *OutputSettings) error
ApplyParameterDocument reads the children of an output:serialization-parameters element into output settings.
root is that element. Each child names one parameter: its local name is the parameter, and a "value" attribute carries the value -- except use-character-maps, which spells its entries out as children because it has no xsl:character-map declaration to point at. The element form is the same one fn:serialize accepts as its second argument.
A parameter in another namespace is an implementation-defined extension the spec allows and this ignores; one in no namespace is a malformed document rather than an extension, since an extension must name its own namespace.
It is exported for the sake of an XQuery main module, whose prolog names this document with "declare option output:parameter-document" (XQuery 3.1 §2.2.4) and gets the same parameters by the same route. The fetching stays with the caller: XSLT resolves the URI against the element that wrote it and XQuery against the query's static base URI, and neither rule belongs to the reading of a document already in hand.
func Serialize ¶ added in v1.2.0
Serialize writes a sequence with the serialization methods of the XSLT and XQuery Serialization 3.1 specification.
The rules it applies are the specification's, not XSLT's: sequence normalisation, the xml, xhtml, html, text, json and adaptive output methods, and the parameters that steer each. Nothing in it is peculiar to a stylesheet. It lives in this package because this is where the serialiser was written, and moving it would be a change to the packages of every existing caller for no gain; but a host other than XSLT — an XQuery main module stating its parameters with "declare option output:*", which is the same specification's other binding — serialises its result through this same function, so that the two agree by construction rather than by maintenance.
charMap is the character map applied to the finished text, or nil. An OutputSettings with an empty Method asks for the default method to be chosen from the sequence itself, which is what a host that stated no method wants; see defaultMethod.
func SerializeAsXML ¶ added in v1.0.0
SerializeAsXML renders a result with the xml output method, ignoring the stylesheet's own xsl:output.
It exists for a caller making a *tree* assertion about a result — the W3C conformance harness is the one in this repository. The stylesheet's method is part of what serialisation means, not part of what the tree is: the html method injects a content-type meta into <head> and writes void elements unclosed, so a result asserted as a tree would be compared against markup the stylesheet never produced, and would not parse back as XML at all.
Indentation and the other settings are deliberately left at their defaults rather than inherited, for the same reason.
func SetSerializationParam ¶ added in v1.2.0
func SetSerializationParam(o *OutputSettings, name, val string) error
SetSerializationParam applies one serialization parameter, named by its local name in the serialization namespace and carrying its lexical value, to a set of output settings.
It is the single place the parameter names of Serialization 3.1 §3 are turned into fields, so that every source of them agrees: an external parameter document read by applyParameterDocument, and an XQuery prolog's "declare option output:*", which states the same parameters in a different syntax and must not acquire a second, subtly different reading of them. xsl:output is not routed through here, because its values arrive already separated into attributes with their own AVT and QName-expansion rules.
An unsupported parameter is SEPM0017 rather than something to ignore: accepting one silently would let a caller believe it had asked for something it did not get.
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 static stylesheet parameters — a
// top-level xsl:param carrying static="yes" — keyed by the parameter's
// {uri}local name. A static parameter is bound before static analysis
// begins, so its value has to come from the caller rather than from
// Transform's runtime Params.
StaticParams map[string]xdm.Sequence
// 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
// SchemaParseOptions are passed to the XML parser for each schema
// document xsl:import-schema loads, including the ones those documents
// import in turn.
//
// The zero value refuses a DOCTYPE, which is the right default for the
// same reason it is in xsd.Options: a schema has no use for one, and it
// is the entry point for entity expansion attacks. A host that must
// read a schema carrying one -- the W3C's own schema for schemas
// declares its entities that way -- sets AllowDOCTYPE here, and thereby
// says so deliberately rather than having it decided for it.
SchemaParseOptions xdm.ParseOptions
// PackageResolver loads the packages named by xsl:use-package. Nil
// disables package composition, for the same reason a nil Resolver
// disables xsl:include: resolving a package name means fetching whatever
// the stylesheet asks for, and a host running an untrusted stylesheet
// should decide what that can reach.
PackageResolver PackageResolver
// XPathVersion pins the version of XPath every expression in the
// stylesheet is compiled in, overriding what the stylesheet declares.
//
// Nil, the default, derives it from the version attribute the way the
// specification requires: 1.0 and 2.0 are XPath 2.0, 3.0 is XPath 3.1,
// since XSLT 3.0 section 2.2 requires an XPath 3.1 processor.
//
// Setting it is for a host that must decide the language itself rather
// than let the document decide — pinning XPath20 to run an untrusted
// stylesheet under a smaller surface, or raising a stylesheet that
// declares 2.0 but is known to want the later functions. It is a
// deliberate departure from conformance in both directions, which is why
// nothing sets it implicitly.
XPathVersion *xpath.Version
// MaxVersion caps the XSLT version whose constructs the compiler will
// accept, whatever the stylesheet's own @version says.
//
// It exists for the constructs a later version *adds* to the language
// rather than changes in it. xsl:package is the case that forces it: a
// package written to XSLT 3.0 routinely carries version="2.0", because
// the version attribute states the XSLT version of the *expressions*, not
// of the packaging — so the attribute cannot tell an XSLT 2.0 processor,
// for which xsl:package is XTSE0010, apart from a 3.0 one for which it is
// the module element. Only the host knows which it is running as.
//
// Zero, the default, imposes no cap and accepts everything implemented.
MaxVersion float64
}
CompileOptions configures compilation.
type DecimalFormat ¶
type DecimalFormat = xpath.DecimalFormat
DecimalFormat holds an xsl:decimal-format declaration.
The type and the formatting engine live in the xpath package, because XPath 3.0 has fn:format-number without a stylesheet to declare a format. This alias keeps the name a stylesheet-facing one: xsl:decimal-format compiles to an xslt.DecimalFormat exactly as it did.
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
// AllowDOCTYPE permits a DOCTYPE declaration in the documents this
// resolver parses. It is off by default, which is what keeps a
// stylesheet from reaching a document that expands entities or names an
// external one — the XXE entry point. A caller whose inputs are trusted,
// a conformance suite among them, can turn it on.
AllowDOCTYPE bool
// ExternalEntities permits the documents this resolver parses to read
// external entities and an external DTD subset, using this same resolver
// — so they are confined to Roots on exactly the terms everything else
// is, with the same scheme rejection and the same symlink handling.
//
// It is separate from AllowDOCTYPE and off by default. AllowDOCTYPE
// admits declarations that cost nothing outside the document; this
// admits reads of other files, which is the XXE surface proper. A caller
// that wants DTD-declared entities does not thereby want file reads, and
// making one imply the other would silently widen every existing caller.
ExternalEntities bool
// UnparsedText permits fn:unparsed-text to read files through this
// resolver, confined to Roots on the same terms as everything else.
//
// It is separate from every other flag here and off by default, because
// it is the widest of them. ResolveDocument hands the stylesheet a
// parsed XML document, so a file that is not well-formed XML discloses
// nothing; unparsed-text hands back the raw bytes of any file inside
// Roots, so a root containing one XML data file and one private key
// leaks the key. A caller who wants fn:doc does not thereby want that,
// and folding the two together would silently widen every existing
// caller of NewFileResolver.
UnparsedText bool
// 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) Preload ¶ added in v1.0.0
func (r *FileResolver) Preload(uri string, tree *xdm.Tree)
Preload records a tree that has already been parsed as the answer for uri, so that a later fn:doc or fn:document naming the same resource hands back the very same nodes rather than a second parse of the same bytes.
Node identity is the point. XSLT 2.0 section 16.1 requires two retrievals of one absolute URI to return the same node, and the test the specification is written for is "fn:doc(fn:document-uri($arg)) is $arg". A caller that parses the principal source itself — every conformance harness does, because it has to annotate the tree before the transform sees it — supplies a document node the resolver has never heard of, and doc() of its own document-uri then parses the file again and answers a different node. Preloading closes that gap without weakening the containment check: the uri still has to resolve to a path inside a permitted root, and an unresolvable one is a no-op.
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) ResolveEntity ¶ added in v1.0.0
func (r *FileResolver) ResolveEntity(systemID, publicID, base string) (io.ReadCloser, string, error)
ResolveEntity implements xdm.EntityResolver, so that a document this resolver parses may read external entities — but only from inside Roots.
Every constraint the rest of this type enforces applies here unchanged, because the path goes through the same resolvePath: a non-file scheme is rejected before the filesystem is touched, symlinks are resolved before the containment check, and a path outside every root is refused. There is nothing entity-specific about the confinement, which is the point — an external entity is a file read like any other, and it gets the same gate rather than a second one written separately and drifting.
The base is the URI of the resource that made the reference, which for an entity declared in an external DTD subset is that subset rather than the document. Resolving against it is XML 1.0 section 4.4.3, and it is why a modular DTD in a subdirectory finds its siblings.
The returned URI is the file: URI of what was actually read, since that is what anything inside the fetched text resolves against.
func (*FileResolver) ResolveModule ¶
ResolveModule implements ModuleResolver for xsl:include and xsl:import.
func (*FileResolver) ResolveText ¶ added in v1.0.0
func (r *FileResolver) ResolveText(uri, base, encoding string) (string, error)
ResolveText implements xpath.TextResolver for fn:unparsed-text.
The path goes through the same resolvePath as every other read this type performs, so the confinement is one implementation rather than two: a non-file scheme is rejected before the filesystem is touched, symlinks are resolved before the containment check, and a path outside every root is refused. UnparsedText only decides *whether* to ask; it does not relax where the answer may come from.
The encoding argument is honoured only for the encodings this package can decode without pulling in a converter. XSLT 2.0 section 16.2 requires an error for an encoding that is not supported, and reporting one is better than silently returning mojibake -- a stylesheet that reads a Shift-JIS file and gets bytes reinterpreted as UTF-8 produces wrong output with no indication anything went wrong.
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
// SuppressIndentation names the elements whose content is written with
// no added whitespace even when indent is yes. It is separate from
// CDataElements despite taking the same kind of list, because the two
// name elements for opposite reasons: one because their text needs no
// escaping, the other because their text must not be disturbed.
SuppressIndentation []xdm.QName
Standalone string
// Version is xsl:output/@version. For the html method it selects the
// HTML version; for xml and xhtml it is the XML version.
Version string
// HTMLVersion is xsl:output/@html-version, new in XSLT 3.0.
//
// It exists because @version cannot answer the question for XHTML: there
// it states the version of XML, so an XHTML5 document is still
// version="1.0" and the HTML version had nowhere to go. Section 9.1: if
// html-version is absent "the html output method uses the value of the
// version parameter in its place", so it overrides for html and is the
// only source for xhtml.
HTMLVersion string
// UseCharacterMaps names the xsl:character-map declarations applied at
// serialisation.
UseCharacterMaps []xdm.QName
// ByteOrderMark writes a BOM at the start of the output. It is "no" by
// default for every method, which is what makes UTF-8 output usable by
// readers that do not expect one.
ByteOrderMark bool
// IncludeContentType controls whether the HTML and XHTML methods insert
// the content-type meta element. It defaults to true, which is why it is
// stored as a pointer: an explicit "no" has to be distinguishable from
// the attribute being absent.
IncludeContentType *bool
// EscapeURIAttributes controls percent-escaping of URI-valued attributes
// in the HTML and XHTML methods. It defaults to true, and is a pointer
// for the same reason.
EscapeURIAttributes *bool
// UndeclarePrefixes emits namespace undeclarations, which only XML 1.1
// permits. This parser implements XML 1.0, so it is recorded and ignored.
UndeclarePrefixes bool
// ItemSeparator is xsl:output/@item-separator: the string inserted
// between adjacent items of the result sequence during sequence
// normalisation (XSLT 3.0 section 5.7.1 step 3).
//
// It is a pointer because an explicit zero-length separator is not the
// same as the attribute being absent: absent means the default rule
// (adjacent atomic values separated by a single space, nodes not
// separated at all), while item-separator="" means every adjacency gets
// nothing, including between two atomic values.
ItemSeparator *string
// BuildTree says whether the raw result is normalised into a final
// result tree before it is delivered or serialised (XSLT 3.0 section
// 2.3.6). Nil is the default, which depends on the method: yes for xml,
// html, xhtml and text, no for json and adaptive.
//
// With build-tree="no" the raw sequence is serialised as it stands, so
// item-separator has something to separate -- normalisation would have
// merged the whole sequence into one tree first, which is why the note
// in 27.1 says the separator "has no effect ... if the effective value
// of build-tree is yes".
BuildTree *bool
// ParameterDocument is the URI of an external
// output:serialization-parameters document whose parameters override the
// ones written here. It is kept as a URI rather than resolved at compile
// time because 25.1 says the document "should be read during run-time
// evaluation of the stylesheet", so that a stylesheet deployed away from
// where it was written still finds its own parameters.
ParameterDocument string
// ParameterDocumentBase is the base URI of the element that wrote
// ParameterDocument, which is what a relative URI there resolves
// against. It has to travel with the URI rather than be taken from the
// principal module: an <xsl:output name="f" parameter-document="p.xml"/>
// in a module reached by xsl:include names a document beside *that*
// module, and output-0722 puts the included module and its parameter
// document in a subdirectory to make the difference visible.
ParameterDocumentBase string
// InlineCharMap is a character map given by value rather than by name:
// the output:use-character-maps element of a parameter document spells
// its entries out, having no xsl:character-map declaration to point at.
// It overrides UseCharacterMaps entirely, being the higher-precedence
// source of the same parameter.
InlineCharMap map[rune]string
// AllowDuplicateNames is the JSON output method's parameter of that name:
// with it unset, two map keys that render to the same JSON string are
// SERE0022 rather than two entries in one object.
AllowDuplicateNames bool
// JSONNodeOutputMethod is the method a node nested inside a JSON value is
// serialised with, JSON having no node type of its own. Empty is the
// default, "xml".
JSONNodeOutputMethod string
// MediaType is the media type of the output. It affects no serialised
// character; it is metadata a caller passes on.
MediaType string
// NormalizationForm names a Unicode normalisation applied to the output.
// Only "none" is implemented; any other value the serialiser does not
// support is a serialization error rather than something to ignore,
// because output that was silently left unnormalised would be accepted
// by a consumer that then compares it against a normalised form and
// finds a spurious difference.
NormalizationForm string
// Version10Implicit records that the principal module declares version
// "1.0" and this is the implicitly-created final result tree.
//
// It changes only the *default* output method. Under backwards
// compatibility an XSLT 1.0 stylesheet has no xhtml method to select —
// the method did not exist — so a result whose document element is html
// in the XHTML namespace serialises as xml, not xhtml: URI-valued
// attributes are left unescaped and no content-type meta element is
// added. An explicit xsl:output/@method overrides this like any other
// default, and xsl:result-document clears the flag, because the tree it
// creates is not the implicit one.
Version10Implicit bool
}
OutputSettings holds the xsl:output declaration.
type PackageResolver ¶ added in v1.1.0
PackageResolver locates the package a use-package declaration names.
A package is addressed by name and version, not by a URI to fetch, so this cannot be folded into ModuleResolver: there is no href to resolve. The resolver is handed the name and the version-matching expression exactly as written, and answers with the tree of the package that best matches, or an error if there is none.
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) Alternatives ¶ added in v1.0.0
Alternatives splits a union pattern into one Pattern per branch.
Section 6.4 says a template rule whose match pattern is a union behaves as if it were several template rules, one per branch, each with the default priority computed for that branch alone. Keeping them fused would give the whole rule the highest branch's priority, so a low-priority branch would outrank templates it should lose to; it would also make xsl:next-match skip the rule entirely after the first branch fired, when the spec has it reconsider the rule for each remaining branch.
func (*Pattern) MatchesReporting ¶ added in v1.1.0
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". MatchesReporting is Matches, additionally reporting the error of the last alternative that failed and was recovered from.
Recovery is right for a pattern that cannot be evaluated against a particular node -- see recoverPatternError -- but the caller sometimes has context that turns the same failure into a stylesheet-level error. The key index builder is the case: an XPST0008 naming a global that is itself being computed is the circularity XTDE0640 describes, and only the builder knows which globals those are.
The recovered error is returned alongside a false match rather than instead of it, so a caller that does not ask keeps the recovering behaviour.
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
// Warnings holds the warnings the transform raised, in the order
// produced. They report conditions the spec asks a processor to notice —
// currently the two xsl:mode warning attributes — and never affect the
// result.
Warnings []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
// BaseURI is the URI this result tree is identified by, which Tree()
// puts on the document node it manufactures. It is empty for the
// principal result, whose document node has no URI of its own; a caller
// assembling a Result from a SecondaryResult sets it from that
// document's BaseURI so that base-uri(/) answers inside it.
BaseURI string
// 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
// BaseURI is Href resolved against the base output URI, which is the
// base URI of every node in this document that does not override it with
// xml:base.
//
// Section 19.1 makes the base output URI implementation-defined when the
// caller does not supply one, and the stylesheet's own location is the
// only URI this engine has: an @href of "out/second.xml" written in a
// stylesheet read from .../foo.xsl means .../out/second.xml, which is
// also where a caller honouring the href would write it. Leaving it
// empty made base-uri() answer "" for every node in a secondary result,
// and made a relative xml:base inside one resolve against nothing.
BaseURI 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
// contains filtered or unexported fields
}
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. The charMap argument overrides the table resolved from the document's own @use-character-maps; passing nil uses that table, which is what a caller almost always wants.
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) SourceDocumentResolver ¶ added in v1.1.0
func (s *Stylesheet) SourceDocumentResolver(inner xpath.DocumentResolver) xpath.DocumentResolver
SourceDocumentResolver wraps a document resolver so that the trees it hands back are whitespace-stripped by this stylesheet's xsl:strip-space and xsl:preserve-space declarations, exactly as Transform strips the ones fn:doc returns during the transformation.
It exists for the one caller that has to evaluate an expression over the source documents *before* the transform begins: the initial match selection is supplied to Transform as a sequence, so whoever computes that sequence computes it outside the transform and would otherwise see unstripped trees the transform itself never sees. Section 4.4 scopes stripping to "all source documents", and a node reaches the transform through the initial match selection as surely as through fn:doc. mode-1802 selects doc('mode-14.xml')//v[position() = 1 to 5] and then indexes the source by position, which counts the whitespace text nodes if they are still there.
Passing nil returns nil, so a caller with no resolver to wrap is unchanged.
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
// Texts resolves fn:unparsed-text. Nil disables it, which is the
// default, and setting Documents does not set this: fn:doc hands back a
// parsed XML document, while fn:unparsed-text hands back the raw bytes
// of whatever the resolver will open. See xpath.TextResolver.
Texts xpath.TextResolver
// 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
// InitialMatchSelection is what the initial apply-templates selects from.
//
// Section 2.3.2 makes the initial match selection an arbitrary sequence,
// not a node: a caller may start the transform at a set of nodes, or —
// since XSLT 3.0 gave patterns the power to match one — at atomic values
// with no source document behind them at all. Leaving it nil defaults the
// selection to the source document, which is the ordinary invocation.
//
// Setting it is also what satisfies XTDE0044: naming an initial mode
// obliges the caller to say what to apply it to, and the source document
// is only the usual way of saying it.
InitialMatchSelection xdm.Sequence
// 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
// InitialTemplateURI is the namespace URI of InitialTemplate, for a
// caller that has already resolved the prefix in its own namespace
// context. Empty means resolve any prefix in InitialTemplate against the
// stylesheet's own declarations instead.
//
// The two are not interchangeable. A caller naming the template from
// outside the stylesheet — a test catalog, a command line with its own
// bindings — binds the prefix itself, and resolving it a second time
// against the stylesheet can silently select a DIFFERENT template that
// happens to spell another namespace with the same prefix.
InitialTemplateURI string
// InitialTemplateParams are the values supplied for the initial
// template's non-tunnel parameters, keyed by the parameter name in Clark
// notation. InitialTemplateTunnelParams are its tunnel parameters, which
// pass through to whatever the template calls in turn.
//
// They are separate from Params, which binds the stylesheet's global
// parameters. Section 2.3.2 makes those two different acts of priming: a
// global parameter belongs to the stylesheet and is set once, while these
// are the arguments of one call, and a template parameter and a global
// parameter may share a name without either standing for the other.
InitialTemplateParams map[string]xdm.Sequence
InitialTemplateTunnelParams map[string]xdm.Sequence
// InitialModeParams and InitialModeTunnelParams are the same thing for an
// apply-templates invocation: section 2.3.3 gives that entry point "two
// sets of (QName, value) pairs, one set for tunnel parameters and one for
// non-tunnel parameters", with "the same [effect] as when a template is
// invoked using xsl:apply-templates with an xsl:with-param child".
//
// They are kept apart from the initial-template pair rather than shared
// with it because the two entry points are mutually exclusive (XTDE0047)
// but the names would still mislead a caller reading the API.
InitialModeParams map[string]xdm.Sequence
InitialModeTunnelParams map[string]xdm.Sequence
// 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
// BaseOutputURI is the URI the principal result tree is destined for.
// Section 19.1 makes it implementation-defined when the caller supplies
// none, and this engine never writes files itself, so the default is to
// have none at all: fn:current-output-uri then answers the empty
// sequence everywhere, and a relative @href on xsl:result-document
// resolves against the stylesheet's own location instead.
BaseOutputURI string
}
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
// IsParam distinguishes an xsl:param from an xsl:variable. The two are
// compiled to the same structure because they evaluate identically, but
// only a parameter can be supplied from outside, and section 10.1.1
// gives the two different error codes when a declared "as" type rejects
// the value: a parameter left unsupplied whose required type excludes
// the empty sequence is XTDE0610, while a variable is only ever the
// plain type error.
IsParam bool
// Tunnel marks a tunnel parameter, which passes through templates that do
// not declare it.
Tunnel bool
// contains filtered or unexported fields
}
Variable is a compiled xsl:variable, xsl:param or xsl:with-param.
Source Files
¶
- abstractcomponent.go
- accumulator.go
- alias.go
- apply.go
- astype.go
- attrset.go
- avt.go
- collate.go
- compile.go
- compile_instr.go
- contextitem.go
- copyfuncs.go
- documentempty.go
- dyncallgrouping.go
- elementtable.go
- entryvisibility.go
- eqname_available.go
- evaluateparams.go
- expandtext.go
- exposecheck.go
- fntransform.go
- fork.go
- formatnumber.go
- funcsig.go
- globalcontextitem.go
- grouping.go
- grouping_absent.go
- grouping_composite.go
- importschema.go
- inheritns.go
- instructions.go
- iterate_static.go
- jsonvalidate.go
- merge.go
- message30.go
- mode30.go
- modeconflict.go
- modevisibility.go
- modewarnings.go
- numberstartat.go
- onempty.go
- outputfuncs.go
- outputpolicy.go
- packageversion.go
- paramdoc.go
- pattern.go
- pattern30.go
- position.go
- prefixnorm.go
- readdocs.go
- resolver.go
- resultdoc.go
- rtfuncs.go
- runtime.go
- seqitems.go
- seqnorm.go
- serialize.go
- sourcedoc.go
- spellnumber.go
- srcpos.go
- static.go
- staticcheck.go
- staticerrors.go
- staticerrors30.go
- stylesheet.go
- sysprops.go
- transform.go
- try.go
- usepackage.go
- usewhen.go
- validate.go
- varfuncs.go
- varparamattrs.go
- xslmap.go