xslt

package module
v0.0.0-...-9629d74 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

README

go-ruby-xslt/xslt

xslt — go-ruby-xslt

Docs License Go Coverage

A pure-Go (no cgo) XSLT 1.0 processor — the deferred XSLT layer of Ruby's Nokogiri. Nokogiri::XSLT is normally a C wrapper over libxslt; this module instead compiles and applies XSLT 1.0 stylesheets over the pure-Go XML DOM and XPath 1.0 engine of go-ruby-nokogiri, so the whole transformation path is CGO-free and cross-compiles to every supported arch.

It is the XSLT backend for go-embedded-ruby but is a standalone, reusable Go module — a sibling of go-ruby-regexp (Onigmo), go-ruby-erb (ERB) and go-ruby-nokogiri (the DOM/XPath core it builds on).

Usage

import (
    "github.com/go-ruby-nokogiri/nokogiri"
    "github.com/go-ruby-xslt/xslt"
)

ss, _ := xslt.ParseString(stylesheetXML)      // compile once
doc, _ := nokogiri.XML(sourceXML)             // parse the source

result, _ := ss.Transform(doc, nil)           // -> *nokogiri.Document (result tree)
out, _    := ss.Apply(doc, nil)               // -> serialized string (xsl:output honoured)

This mirrors the Ruby surface:

Nokogiri::XSLT(stylesheet).transform(doc)   # -> result document   == ss.Transform
Nokogiri::XSLT(stylesheet).apply_to(doc)    # -> serialized string == ss.Apply

Stylesheet parameters are passed as a map[string]any whose values are string, float64, bool or *nokogiri.NodeSet.

Multi-document stylesheets (xsl:include / xsl:import)

xsl:include and xsl:import are fully supported. Because fetching the referenced stylesheet is a policy decision (in-memory bundle, filesystem, network), it goes through a Resolver seam rather than assuming a filesystem:

res := xslt.MapResolver{                         // in-memory; no filesystem
    "base.xsl": baseStylesheetXML,
}
ss, _ := xslt.ParseStringWithResolver(mainXML, res)   // or ParseWithResolver(doc, res)
  • xsl:include splices the included stylesheet's templates, variables, keys, etc. at the same import precedence as the including stylesheet.
  • xsl:import brings them in at a lower import precedence; a later import outranks an earlier one, and an importing stylesheet outranks everything it imports (XSLT 1.0 §2.6.2). Conflicts resolve by import precedence → priority → document order, and xsl:apply-imports re-applies the current node against the matching rule of next-lower precedence in the current mode.
  • Provide a Resolver (MapResolver, ResolverFunc, or your own) — a stylesheet that references include/import with no resolver configured fails to compile with a clear error rather than silently dropping the reference. Resolve(href, base) also returns a base URI so nested relative references resolve correctly.

XSLT 1.0 coverage

Stylesheet structure and template rules:

  • xsl:stylesheet / xsl:transform (version, namespaces); literal-result-element stylesheets (a root element carrying xsl:version).
  • xsl:include / xsl:import (multi-document stylesheets via the Resolver seam — see below), with full import-precedence conflict resolution.
  • Template rules: match, name, priority, mode; conflict resolution by import precedence → priority → document order; the built-in default template rules for every node kind; xsl:apply-imports (re-applies the next-lower import precedence rule).

Instructions:

  • xsl:value-of, xsl:for-each, xsl:if, xsl:choose / when / otherwise
  • xsl:apply-templates (select, mode), xsl:call-template, xsl:with-param
  • xsl:variable, xsl:param (top-level + local; caller-overridable params)
  • xsl:copy, xsl:copy-of (deep copy of node-sets and RTFs)
  • xsl:element, xsl:attribute, xsl:text, xsl:comment, xsl:processing-instruction, xsl:attribute-set (with use-attribute-sets)
  • xsl:sort (data-type, order, multiple keys), xsl:number (single/any level; 1, 01, a, A, i, I formats)
  • xsl:key + key(), xsl:decimal-format + format-number()
  • xsl:output (method = xml/html/text, indent, encoding, omit-xml-declaration, standalone, doctype, cdata-section-elements)
  • literal result elements + attribute-value templates ({expr}), namespace declarations on result elements
  • XSLT function library: key, format-number, current, generate-id, system-property, element-available, function-available, unparsed-entity-uri
Out of scope

This is a 1.0 processor. XSLT 2.0 / XPath 2.0 features are genuinely outside the XSLT 1.0 specification and are therefore out of scope — they are not faked: sequences and the XPath 2.0 data model, xsl:function, xsl:for-each-group (grouping), schema-aware processing (xsl:import-schema, type annotations), and tunnel parameters. document() of an external URI still needs a URI resolver and is not wired up; disable-output-escaping is accepted but emits normally.

Built on go-ruby-nokogiri

The XPath 1.0 engine is not reimplemented here. This module drives go-ruby-nokogiri's engine through its extension seam (XPathContext): XSLT variable bindings ($name), an extension-function resolver for the XSLT function library, and XSLT current() semantics. Requires github.com/go-ruby-nokogiri/nokogiri at the revision that exposes that seam.

Tests & coverage

go test -race with a 100% coverage gate, on Linux/macOS/Windows and the six 64-bit Go targets (amd64, arm64, riscv64, loong64, ppc64le, s390x). Deterministic golden vectors (stylesheet + source → expected output, drawn from the XSLT 1.0 spec) hold coverage with no Ruby present; a differential oracle against Nokogiri::XSLT (libxslt) runs where a new-enough Ruby is available (version-gated on RUBY_VERSION >= "4.0").

License

BSD-3-Clause — see LICENSE. Copyright the go-ruby-xslt/xslt authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package xslt is a pure-Go (CGO_ENABLED=0) XSLT 1.0 transformation engine, the deferred XSLT layer of the go-ruby Nokogiri stack. Ruby's Nokogiri::XSLT is a C wrapper over libxslt; this package instead compiles and applies XSLT 1.0 stylesheets over the pure-Go XML DOM and XPath 1.0 engine provided by github.com/go-ruby-nokogiri/nokogiri, so the whole path stays CGO-free.

Model

A stylesheet is compiled once with Parse (or ParseString) and then applied to any number of source documents with (*Stylesheet).Transform, mirroring

Nokogiri::XSLT(xslt_string).transform(doc)          # -> result document
Nokogiri::XSLT(xslt_string).apply_to(doc)           # -> serialized string

Transform returns the result tree as a *nokogiri.Document; Apply returns the serialized output string honouring xsl:output (method/indent/encoding/ omit-xml-declaration). Stylesheet parameters are passed as a map[string]any whose values are string, float64, bool or *nokogiri.NodeSet.

Coverage

The engine implements XSLT 1.0: xsl:stylesheet/transform, xsl:include and xsl:import (multi-document stylesheets, fetched through a Resolver) with full import-precedence conflict resolution, template rules (match/name/priority/ mode), apply-templates/call-template/apply-imports with conflict resolution by import precedence then priority then document order, the built-in default template rules, and the instruction set: value-of, for-each, if, choose/when/otherwise, variable/param/with-param, copy/copy-of, element/attribute/text/comment/processing-instruction, attribute-set, sort, number, key/key(), literal result elements with attribute-value templates, namespace handling on result elements, xsl:output, and the XSLT function library (document, key, format-number with decimal-format, current, generate-id, system-property, element-available, function-available, unparsed-entity-uri). xsl:decimal-format is honoured by format-number.

Resolving xsl:include / xsl:import

Fetching the stylesheet referenced by an xsl:include or xsl:import is done through the Resolver seam, so compilation needs no filesystem or network of its own. Use ParseStringWithResolver / ParseWithResolver and pass a MapResolver (in-memory), a ResolverFunc, or a custom Resolver. Plain ParseString / Parse have no resolver and reject stylesheets that reference include/import.

Out of scope

XSLT 2.0 / XPath 2.0 features are outside the XSLT 1.0 specification and are not emulated: sequences and the XPath 2.0 data model, xsl:function, xsl:for-each-group (grouping), schema-aware processing (xsl:import-schema, type annotations) and tunnel parameters. This is a 1.0 processor.

Index

Constants

View Source
const Version = "1.0"

Version is the XSLT version this processor implements.

Variables

This section is empty.

Functions

This section is empty.

Types

type Document

type Document = nokogiri.Document

Document is a nokogiri XML document (the source or the result tree).

type MapResolver

type MapResolver map[string]string

MapResolver resolves hrefs from an in-memory map keyed by the exact href string. It is the convenient resolver for tests and for self-contained stylesheet bundles: no filesystem is touched. The base URI is not consulted; each returned module's base URI is its own href, so nested includes/imports are looked up by their own href keys.

func (MapResolver) Resolve

func (m MapResolver) Resolve(href, base string) (string, string, error)

Resolve looks up href in the map.

type Node

type Node = nokogiri.Node

Node is a nokogiri DOM node.

type NodeSet

type NodeSet = nokogiri.NodeSet

NodeSet is a nokogiri node-set (a node-set-valued parameter or result).

type Resolver

type Resolver interface {
	Resolve(href, base string) (source string, resolvedBase string, err error)
}

Resolver fetches the source text of a stylesheet referenced by xsl:include or xsl:import. Resolve receives the raw value of the href attribute and the base URI of the referencing stylesheet module (empty for the top-level stylesheet). It returns the referenced stylesheet source and the base URI to associate with it (used to resolve hrefs nested inside the returned stylesheet).

The seam keeps compilation free of any filesystem or network dependency: a stylesheet bundle can be resolved entirely in memory (see MapResolver) or from disk with a small ResolverFunc. When a stylesheet references xsl:include or xsl:import and no Resolver is configured, compilation fails with a clear error rather than silently dropping the reference.

type ResolverFunc

type ResolverFunc func(href, base string) (string, string, error)

ResolverFunc adapts an ordinary function to the Resolver interface.

func (ResolverFunc) Resolve

func (f ResolverFunc) Resolve(href, base string) (string, string, error)

Resolve calls f.

type Stylesheet

type Stylesheet struct {
	// contains filtered or unexported fields
}

Stylesheet is a compiled XSLT 1.0 stylesheet, ready to Transform any number of source documents.

func Parse

func Parse(doc *nokogiri.Document) (*Stylesheet, error)

Parse compiles an already-parsed stylesheet document. A stylesheet that uses xsl:include or xsl:import needs a Resolver; use ParseWithResolver for those.

func ParseString

func ParseString(src string) (*Stylesheet, error)

ParseString compiles an XSLT stylesheet from its source text. A stylesheet that uses xsl:include or xsl:import needs a Resolver; use ParseStringWithResolver for those.

func ParseStringWithResolver

func ParseStringWithResolver(src string, r Resolver) (*Stylesheet, error)

ParseStringWithResolver compiles an XSLT stylesheet from its source text, fetching any xsl:include / xsl:import references through r.

func ParseWithResolver

func ParseWithResolver(doc *nokogiri.Document, r Resolver) (*Stylesheet, error)

ParseWithResolver compiles an already-parsed stylesheet document, fetching any xsl:include / xsl:import references through r.

func (*Stylesheet) Apply

func (s *Stylesheet) Apply(src *nokogiri.Document, params map[string]any) (string, error)

Apply is Transform followed by serialization honouring xsl:output; it mirrors Nokogiri::XSLT#apply_to (a string result).

func (*Stylesheet) Transform

func (s *Stylesheet) Transform(src *nokogiri.Document, params map[string]any) (*nokogiri.Document, error)

Transform applies the compiled stylesheet to src with the given parameters and returns the result tree as a new document.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL