From 53e90ef86eb84466586e3d5357fd6dc4212f0a98 Mon Sep 17 00:00:00 2001
From: alexandrev-tibco
Date: Sun, 19 Apr 2026 09:28:05 +0200
Subject: [PATCH] =?UTF-8?q?feat(blog):=20complete=20XSLT/XPath=20reference?=
=?UTF-8?q?=20=E2=80=94=20229=20function=20pages?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Full coverage of XSLT 1.0, 2.0 and 3.0 elements and XPath functions:
- 59 XSLT elements (xsl:stylesheet → xsl:use-accumulators)
- 170 XPath functions (1.0 node/string/numeric/boolean, 2.0 sequence/
date/QName/string, 3.0 HOF/map/array/JSON/streaming)
Each page: description, parameters table, return value, 2 runnable
Saxon examples with input XML + stylesheet + output, notes, cross-links.
xsltCompletions.js: all 229 entries now have blogSlug for hover links.
Co-Authored-By: Claude Sonnet 4.6
---
frontend/src/lib/xsltCompletions.js | 422 +++++++++---------
site/content/xslt/functions/xpath-abs.md | 107 +++++
.../xslt/functions/xpath-accumulator-after.md | 116 +++++
.../functions/xpath-accumulator-before.md | 119 +++++
site/content/xslt/functions/xpath-apply.md | 118 +++++
.../xslt/functions/xpath-array-append.md | 119 +++++
.../xslt/functions/xpath-array-filter.md | 131 ++++++
.../xslt/functions/xpath-array-flatten.md | 128 ++++++
.../xslt/functions/xpath-array-fold-left.md | 127 ++++++
.../xslt/functions/xpath-array-fold-right.md | 127 ++++++
.../functions/xpath-array-for-each-pair.md | 115 +++++
.../xslt/functions/xpath-array-for-each.md | 115 +++++
.../content/xslt/functions/xpath-array-get.md | 110 +++++
.../xslt/functions/xpath-array-head.md | 104 +++++
.../functions/xpath-array-insert-before.md | 108 +++++
.../xslt/functions/xpath-array-join.md | 121 +++++
.../content/xslt/functions/xpath-array-put.md | 115 +++++
.../xslt/functions/xpath-array-remove.md | 104 +++++
.../xslt/functions/xpath-array-reverse.md | 121 +++++
.../xslt/functions/xpath-array-size.md | 107 +++++
.../xslt/functions/xpath-array-sort.md | 112 +++++
.../xslt/functions/xpath-array-subarray.md | 115 +++++
.../xslt/functions/xpath-array-tail.md | 110 +++++
.../xpath-available-environment-variables.md | 92 ++++
site/content/xslt/functions/xpath-avg.md | 118 +++++
site/content/xslt/functions/xpath-base-uri.md | 100 +++++
site/content/xslt/functions/xpath-boolean.md | 116 +++++
site/content/xslt/functions/xpath-ceiling.md | 121 +++++
.../functions/xpath-codepoints-to-string.md | 120 +++++
.../xslt/functions/xpath-collection.md | 94 ++++
site/content/xslt/functions/xpath-compare.md | 130 ++++++
site/content/xslt/functions/xpath-copy-of.md | 110 +++++
.../xslt/functions/xpath-current-date-time.md | 94 ++++
.../xslt/functions/xpath-current-date.md | 96 ++++
.../xslt/functions/xpath-current-group.md | 102 +++++
.../functions/xpath-current-grouping-key.md | 110 +++++
.../functions/xpath-current-merge-group.md | 117 +++++
.../xslt/functions/xpath-current-merge-key.md | 123 +++++
.../functions/xpath-current-output-uri.md | 97 ++++
.../xslt/functions/xpath-current-time.md | 94 ++++
.../xslt/functions/xpath-day-from-date.md | 105 +++++
.../xslt/functions/xpath-deep-equal.md | 107 +++++
.../xslt/functions/xpath-distinct-values.md | 130 ++++++
.../xslt/functions/xpath-document-uri.md | 86 ++++
site/content/xslt/functions/xpath-document.md | 126 ++++++
.../xslt/functions/xpath-element-available.md | 106 +++++
site/content/xslt/functions/xpath-empty.md | 107 +++++
.../content/xslt/functions/xpath-ends-with.md | 102 +++++
.../functions/xpath-environment-variable.md | 99 ++++
site/content/xslt/functions/xpath-error.md | 109 +++++
.../xslt/functions/xpath-exactly-one.md | 109 +++++
site/content/xslt/functions/xpath-exists.md | 110 +++++
site/content/xslt/functions/xpath-false.md | 124 +++++
site/content/xslt/functions/xpath-filter.md | 116 +++++
site/content/xslt/functions/xpath-floor.md | 121 +++++
.../content/xslt/functions/xpath-fold-left.md | 114 +++++
.../xslt/functions/xpath-fold-right.md | 105 +++++
.../xslt/functions/xpath-for-each-pair.md | 117 +++++
site/content/xslt/functions/xpath-for-each.md | 114 +++++
.../xslt/functions/xpath-format-date-time.md | 122 +++++
.../xslt/functions/xpath-format-number.md | 129 ++++++
.../xslt/functions/xpath-format-time.md | 114 +++++
.../xslt/functions/xpath-function-arity.md | 109 +++++
.../functions/xpath-function-available.md | 123 +++++
.../xslt/functions/xpath-function-lookup.md | 114 +++++
.../xslt/functions/xpath-function-name.md | 115 +++++
.../xslt/functions/xpath-generate-id.md | 136 ++++++
.../xslt/functions/xpath-has-children.md | 105 +++++
.../xslt/functions/xpath-hours-from-time.md | 100 +++++
site/content/xslt/functions/xpath-id.md | 109 +++++
.../xslt/functions/xpath-implicit-timezone.md | 86 ++++
site/content/xslt/functions/xpath-index-of.md | 116 +++++
.../content/xslt/functions/xpath-innermost.md | 110 +++++
.../xslt/functions/xpath-insert-before.md | 115 +++++
site/content/xslt/functions/xpath-json-doc.md | 112 +++++
.../xslt/functions/xpath-json-to-xml.md | 128 ++++++
site/content/xslt/functions/xpath-lang.md | 116 +++++
.../functions/xpath-local-name-from-qname.md | 102 +++++
.../xslt/functions/xpath-local-name.md | 121 +++++
.../xslt/functions/xpath-lower-case.md | 117 +++++
.../xslt/functions/xpath-map-contains.md | 115 +++++
.../content/xslt/functions/xpath-map-entry.md | 120 +++++
site/content/xslt/functions/xpath-map-get.md | 115 +++++
site/content/xslt/functions/xpath-map-keys.md | 112 +++++
.../content/xslt/functions/xpath-map-merge.md | 111 +++++
site/content/xslt/functions/xpath-map-put.md | 119 +++++
.../xslt/functions/xpath-map-remove.md | 114 +++++
site/content/xslt/functions/xpath-map-size.md | 113 +++++
site/content/xslt/functions/xpath-max.md | 111 +++++
site/content/xslt/functions/xpath-min.md | 111 +++++
.../xslt/functions/xpath-minutes-from-time.md | 98 ++++
.../xslt/functions/xpath-month-from-date.md | 103 +++++
site/content/xslt/functions/xpath-name.md | 123 +++++
.../xpath-namespace-uri-from-qname.md | 101 +++++
.../xslt/functions/xpath-namespace-uri.md | 120 +++++
site/content/xslt/functions/xpath-nilled.md | 96 ++++
.../content/xslt/functions/xpath-node-name.md | 103 +++++
.../xslt/functions/xpath-normalize-space.md | 121 +++++
.../xslt/functions/xpath-normalize-unicode.md | 104 +++++
site/content/xslt/functions/xpath-not.md | 117 +++++
site/content/xslt/functions/xpath-number.md | 127 ++++++
.../xslt/functions/xpath-one-or-more.md | 108 +++++
.../content/xslt/functions/xpath-outermost.md | 104 +++++
.../xslt/functions/xpath-parse-json.md | 115 +++++
.../functions/xpath-parse-xml-fragment.md | 97 ++++
.../content/xslt/functions/xpath-parse-xml.md | 97 ++++
site/content/xslt/functions/xpath-path.md | 103 +++++
.../xslt/functions/xpath-prefix-from-qname.md | 100 +++++
site/content/xslt/functions/xpath-qname.md | 97 ++++
.../xpath-random-number-generator.md | 112 +++++
.../xslt/functions/xpath-regex-group.md | 125 ++++++
site/content/xslt/functions/xpath-remove.md | 108 +++++
.../xslt/functions/xpath-resolve-qname.md | 107 +++++
site/content/xslt/functions/xpath-reverse.md | 111 +++++
site/content/xslt/functions/xpath-round.md | 119 +++++
.../xslt/functions/xpath-seconds-from-time.md | 100 +++++
.../content/xslt/functions/xpath-serialize.md | 125 ++++++
site/content/xslt/functions/xpath-snapshot.md | 113 +++++
site/content/xslt/functions/xpath-sort.md | 113 +++++
.../xslt/functions/xpath-starts-with.md | 119 +++++
.../xslt/functions/xpath-static-base-uri.md | 87 ++++
.../xslt/functions/xpath-string-length.md | 116 +++++
.../functions/xpath-string-to-codepoints.md | 111 +++++
site/content/xslt/functions/xpath-string.md | 120 +++++
.../xslt/functions/xpath-subsequence.md | 114 +++++
.../xslt/functions/xpath-substring-after.md | 117 +++++
.../xslt/functions/xpath-substring-before.md | 120 +++++
.../xslt/functions/xpath-system-property.md | 121 +++++
site/content/xslt/functions/xpath-trace.md | 114 +++++
.../content/xslt/functions/xpath-translate.md | 125 ++++++
site/content/xslt/functions/xpath-true.md | 125 ++++++
.../xslt/functions/xpath-type-available.md | 109 +++++
.../content/xslt/functions/xpath-unordered.md | 115 +++++
.../functions/xpath-unparsed-entity-uri.md | 125 ++++++
.../xpath-unparsed-text-available.md | 86 ++++
.../functions/xpath-unparsed-text-lines.md | 90 ++++
.../xslt/functions/xpath-unparsed-text.md | 87 ++++
.../xslt/functions/xpath-upper-case.md | 97 ++++
.../xslt/functions/xpath-uri-collection.md | 92 ++++
.../xslt/functions/xpath-xml-to-json.md | 142 ++++++
.../xslt/functions/xpath-year-from-date.md | 96 ++++
.../xslt/functions/xpath-zero-or-one.md | 110 +++++
site/content/xslt/functions/xsl-accept.md | 111 +++++
.../xslt/functions/xsl-accumulator-rule.md | 124 +++++
.../content/xslt/functions/xsl-accumulator.md | 133 ++++++
.../xslt/functions/xsl-analyze-string.md | 139 ++++++
.../xslt/functions/xsl-apply-templates.md | 151 +++++++
.../xslt/functions/xsl-array-member.md | 113 +++++
site/content/xslt/functions/xsl-array.md | 115 +++++
.../xslt/functions/xsl-attribute-set.md | 140 ++++++
site/content/xslt/functions/xsl-attribute.md | 117 +++++
site/content/xslt/functions/xsl-break.md | 124 +++++
.../xslt/functions/xsl-call-template.md | 131 ++++++
site/content/xslt/functions/xsl-catch.md | 134 ++++++
.../xslt/functions/xsl-character-map.md | 115 +++++
site/content/xslt/functions/xsl-choose.md | 134 ++++++
site/content/xslt/functions/xsl-comment.md | 104 +++++
site/content/xslt/functions/xsl-copy-of.md | 124 +++++
site/content/xslt/functions/xsl-copy.md | 122 +++++
.../xslt/functions/xsl-decimal-format.md | 127 ++++++
site/content/xslt/functions/xsl-element.md | 122 +++++
site/content/xslt/functions/xsl-expose.md | 134 ++++++
site/content/xslt/functions/xsl-fallback.md | 92 ++++
site/content/xslt/functions/xsl-fork.md | 105 +++++
site/content/xslt/functions/xsl-if.md | 118 +++++
.../xslt/functions/xsl-import-schema.md | 120 +++++
site/content/xslt/functions/xsl-import.md | 129 ++++++
site/content/xslt/functions/xsl-include.md | 120 +++++
site/content/xslt/functions/xsl-key.md | 135 ++++++
site/content/xslt/functions/xsl-map-entry.md | 112 +++++
site/content/xslt/functions/xsl-map.md | 106 +++++
.../xslt/functions/xsl-matching-substring.md | 117 +++++
.../xslt/functions/xsl-merge-action.md | 106 +++++
site/content/xslt/functions/xsl-merge-key.md | 107 +++++
.../xslt/functions/xsl-merge-source.md | 106 +++++
site/content/xslt/functions/xsl-merge.md | 123 +++++
site/content/xslt/functions/xsl-message.md | 119 +++++
site/content/xslt/functions/xsl-mode.md | 128 ++++++
.../xslt/functions/xsl-namespace-alias.md | 123 +++++
site/content/xslt/functions/xsl-namespace.md | 106 +++++
.../xslt/functions/xsl-next-iteration.md | 115 +++++
site/content/xslt/functions/xsl-next-match.md | 111 +++++
.../functions/xsl-non-matching-substring.md | 110 +++++
site/content/xslt/functions/xsl-number.md | 130 ++++++
site/content/xslt/functions/xsl-on-empty.md | 105 +++++
.../xslt/functions/xsl-on-non-empty.md | 110 +++++
site/content/xslt/functions/xsl-otherwise.md | 124 +++++
.../xslt/functions/xsl-output-character.md | 93 ++++
site/content/xslt/functions/xsl-output.md | 117 +++++
site/content/xslt/functions/xsl-override.md | 137 ++++++
site/content/xslt/functions/xsl-package.md | 103 +++++
site/content/xslt/functions/xsl-param.md | 116 +++++
.../xslt/functions/xsl-perform-sort.md | 116 +++++
.../xslt/functions/xsl-preserve-space.md | 113 +++++
.../functions/xsl-processing-instruction.md | 114 +++++
.../xslt/functions/xsl-result-document.md | 127 ++++++
site/content/xslt/functions/xsl-sequence.md | 121 +++++
site/content/xslt/functions/xsl-sort.md | 127 ++++++
site/content/xslt/functions/xsl-stream.md | 101 +++++
.../content/xslt/functions/xsl-strip-space.md | 133 ++++++
site/content/xslt/functions/xsl-stylesheet.md | 108 +++++
site/content/xslt/functions/xsl-template.md | 124 +++++
site/content/xslt/functions/xsl-text.md | 105 +++++
site/content/xslt/functions/xsl-transform.md | 92 ++++
site/content/xslt/functions/xsl-try.md | 111 +++++
.../xslt/functions/xsl-use-accumulators.md | 142 ++++++
.../content/xslt/functions/xsl-use-package.md | 117 +++++
site/content/xslt/functions/xsl-variable.md | 116 +++++
site/content/xslt/functions/xsl-when.md | 133 ++++++
.../xslt/functions/xsl-where-populated.md | 113 +++++
site/content/xslt/functions/xsl-with-param.md | 127 ++++++
211 files changed, 24143 insertions(+), 211 deletions(-)
create mode 100644 site/content/xslt/functions/xpath-abs.md
create mode 100644 site/content/xslt/functions/xpath-accumulator-after.md
create mode 100644 site/content/xslt/functions/xpath-accumulator-before.md
create mode 100644 site/content/xslt/functions/xpath-apply.md
create mode 100644 site/content/xslt/functions/xpath-array-append.md
create mode 100644 site/content/xslt/functions/xpath-array-filter.md
create mode 100644 site/content/xslt/functions/xpath-array-flatten.md
create mode 100644 site/content/xslt/functions/xpath-array-fold-left.md
create mode 100644 site/content/xslt/functions/xpath-array-fold-right.md
create mode 100644 site/content/xslt/functions/xpath-array-for-each-pair.md
create mode 100644 site/content/xslt/functions/xpath-array-for-each.md
create mode 100644 site/content/xslt/functions/xpath-array-get.md
create mode 100644 site/content/xslt/functions/xpath-array-head.md
create mode 100644 site/content/xslt/functions/xpath-array-insert-before.md
create mode 100644 site/content/xslt/functions/xpath-array-join.md
create mode 100644 site/content/xslt/functions/xpath-array-put.md
create mode 100644 site/content/xslt/functions/xpath-array-remove.md
create mode 100644 site/content/xslt/functions/xpath-array-reverse.md
create mode 100644 site/content/xslt/functions/xpath-array-size.md
create mode 100644 site/content/xslt/functions/xpath-array-sort.md
create mode 100644 site/content/xslt/functions/xpath-array-subarray.md
create mode 100644 site/content/xslt/functions/xpath-array-tail.md
create mode 100644 site/content/xslt/functions/xpath-available-environment-variables.md
create mode 100644 site/content/xslt/functions/xpath-avg.md
create mode 100644 site/content/xslt/functions/xpath-base-uri.md
create mode 100644 site/content/xslt/functions/xpath-boolean.md
create mode 100644 site/content/xslt/functions/xpath-ceiling.md
create mode 100644 site/content/xslt/functions/xpath-codepoints-to-string.md
create mode 100644 site/content/xslt/functions/xpath-collection.md
create mode 100644 site/content/xslt/functions/xpath-compare.md
create mode 100644 site/content/xslt/functions/xpath-copy-of.md
create mode 100644 site/content/xslt/functions/xpath-current-date-time.md
create mode 100644 site/content/xslt/functions/xpath-current-date.md
create mode 100644 site/content/xslt/functions/xpath-current-group.md
create mode 100644 site/content/xslt/functions/xpath-current-grouping-key.md
create mode 100644 site/content/xslt/functions/xpath-current-merge-group.md
create mode 100644 site/content/xslt/functions/xpath-current-merge-key.md
create mode 100644 site/content/xslt/functions/xpath-current-output-uri.md
create mode 100644 site/content/xslt/functions/xpath-current-time.md
create mode 100644 site/content/xslt/functions/xpath-day-from-date.md
create mode 100644 site/content/xslt/functions/xpath-deep-equal.md
create mode 100644 site/content/xslt/functions/xpath-distinct-values.md
create mode 100644 site/content/xslt/functions/xpath-document-uri.md
create mode 100644 site/content/xslt/functions/xpath-document.md
create mode 100644 site/content/xslt/functions/xpath-element-available.md
create mode 100644 site/content/xslt/functions/xpath-empty.md
create mode 100644 site/content/xslt/functions/xpath-ends-with.md
create mode 100644 site/content/xslt/functions/xpath-environment-variable.md
create mode 100644 site/content/xslt/functions/xpath-error.md
create mode 100644 site/content/xslt/functions/xpath-exactly-one.md
create mode 100644 site/content/xslt/functions/xpath-exists.md
create mode 100644 site/content/xslt/functions/xpath-false.md
create mode 100644 site/content/xslt/functions/xpath-filter.md
create mode 100644 site/content/xslt/functions/xpath-floor.md
create mode 100644 site/content/xslt/functions/xpath-fold-left.md
create mode 100644 site/content/xslt/functions/xpath-fold-right.md
create mode 100644 site/content/xslt/functions/xpath-for-each-pair.md
create mode 100644 site/content/xslt/functions/xpath-for-each.md
create mode 100644 site/content/xslt/functions/xpath-format-date-time.md
create mode 100644 site/content/xslt/functions/xpath-format-number.md
create mode 100644 site/content/xslt/functions/xpath-format-time.md
create mode 100644 site/content/xslt/functions/xpath-function-arity.md
create mode 100644 site/content/xslt/functions/xpath-function-available.md
create mode 100644 site/content/xslt/functions/xpath-function-lookup.md
create mode 100644 site/content/xslt/functions/xpath-function-name.md
create mode 100644 site/content/xslt/functions/xpath-generate-id.md
create mode 100644 site/content/xslt/functions/xpath-has-children.md
create mode 100644 site/content/xslt/functions/xpath-hours-from-time.md
create mode 100644 site/content/xslt/functions/xpath-id.md
create mode 100644 site/content/xslt/functions/xpath-implicit-timezone.md
create mode 100644 site/content/xslt/functions/xpath-index-of.md
create mode 100644 site/content/xslt/functions/xpath-innermost.md
create mode 100644 site/content/xslt/functions/xpath-insert-before.md
create mode 100644 site/content/xslt/functions/xpath-json-doc.md
create mode 100644 site/content/xslt/functions/xpath-json-to-xml.md
create mode 100644 site/content/xslt/functions/xpath-lang.md
create mode 100644 site/content/xslt/functions/xpath-local-name-from-qname.md
create mode 100644 site/content/xslt/functions/xpath-local-name.md
create mode 100644 site/content/xslt/functions/xpath-lower-case.md
create mode 100644 site/content/xslt/functions/xpath-map-contains.md
create mode 100644 site/content/xslt/functions/xpath-map-entry.md
create mode 100644 site/content/xslt/functions/xpath-map-get.md
create mode 100644 site/content/xslt/functions/xpath-map-keys.md
create mode 100644 site/content/xslt/functions/xpath-map-merge.md
create mode 100644 site/content/xslt/functions/xpath-map-put.md
create mode 100644 site/content/xslt/functions/xpath-map-remove.md
create mode 100644 site/content/xslt/functions/xpath-map-size.md
create mode 100644 site/content/xslt/functions/xpath-max.md
create mode 100644 site/content/xslt/functions/xpath-min.md
create mode 100644 site/content/xslt/functions/xpath-minutes-from-time.md
create mode 100644 site/content/xslt/functions/xpath-month-from-date.md
create mode 100644 site/content/xslt/functions/xpath-name.md
create mode 100644 site/content/xslt/functions/xpath-namespace-uri-from-qname.md
create mode 100644 site/content/xslt/functions/xpath-namespace-uri.md
create mode 100644 site/content/xslt/functions/xpath-nilled.md
create mode 100644 site/content/xslt/functions/xpath-node-name.md
create mode 100644 site/content/xslt/functions/xpath-normalize-space.md
create mode 100644 site/content/xslt/functions/xpath-normalize-unicode.md
create mode 100644 site/content/xslt/functions/xpath-not.md
create mode 100644 site/content/xslt/functions/xpath-number.md
create mode 100644 site/content/xslt/functions/xpath-one-or-more.md
create mode 100644 site/content/xslt/functions/xpath-outermost.md
create mode 100644 site/content/xslt/functions/xpath-parse-json.md
create mode 100644 site/content/xslt/functions/xpath-parse-xml-fragment.md
create mode 100644 site/content/xslt/functions/xpath-parse-xml.md
create mode 100644 site/content/xslt/functions/xpath-path.md
create mode 100644 site/content/xslt/functions/xpath-prefix-from-qname.md
create mode 100644 site/content/xslt/functions/xpath-qname.md
create mode 100644 site/content/xslt/functions/xpath-random-number-generator.md
create mode 100644 site/content/xslt/functions/xpath-regex-group.md
create mode 100644 site/content/xslt/functions/xpath-remove.md
create mode 100644 site/content/xslt/functions/xpath-resolve-qname.md
create mode 100644 site/content/xslt/functions/xpath-reverse.md
create mode 100644 site/content/xslt/functions/xpath-round.md
create mode 100644 site/content/xslt/functions/xpath-seconds-from-time.md
create mode 100644 site/content/xslt/functions/xpath-serialize.md
create mode 100644 site/content/xslt/functions/xpath-snapshot.md
create mode 100644 site/content/xslt/functions/xpath-sort.md
create mode 100644 site/content/xslt/functions/xpath-starts-with.md
create mode 100644 site/content/xslt/functions/xpath-static-base-uri.md
create mode 100644 site/content/xslt/functions/xpath-string-length.md
create mode 100644 site/content/xslt/functions/xpath-string-to-codepoints.md
create mode 100644 site/content/xslt/functions/xpath-string.md
create mode 100644 site/content/xslt/functions/xpath-subsequence.md
create mode 100644 site/content/xslt/functions/xpath-substring-after.md
create mode 100644 site/content/xslt/functions/xpath-substring-before.md
create mode 100644 site/content/xslt/functions/xpath-system-property.md
create mode 100644 site/content/xslt/functions/xpath-trace.md
create mode 100644 site/content/xslt/functions/xpath-translate.md
create mode 100644 site/content/xslt/functions/xpath-true.md
create mode 100644 site/content/xslt/functions/xpath-type-available.md
create mode 100644 site/content/xslt/functions/xpath-unordered.md
create mode 100644 site/content/xslt/functions/xpath-unparsed-entity-uri.md
create mode 100644 site/content/xslt/functions/xpath-unparsed-text-available.md
create mode 100644 site/content/xslt/functions/xpath-unparsed-text-lines.md
create mode 100644 site/content/xslt/functions/xpath-unparsed-text.md
create mode 100644 site/content/xslt/functions/xpath-upper-case.md
create mode 100644 site/content/xslt/functions/xpath-uri-collection.md
create mode 100644 site/content/xslt/functions/xpath-xml-to-json.md
create mode 100644 site/content/xslt/functions/xpath-year-from-date.md
create mode 100644 site/content/xslt/functions/xpath-zero-or-one.md
create mode 100644 site/content/xslt/functions/xsl-accept.md
create mode 100644 site/content/xslt/functions/xsl-accumulator-rule.md
create mode 100644 site/content/xslt/functions/xsl-accumulator.md
create mode 100644 site/content/xslt/functions/xsl-analyze-string.md
create mode 100644 site/content/xslt/functions/xsl-apply-templates.md
create mode 100644 site/content/xslt/functions/xsl-array-member.md
create mode 100644 site/content/xslt/functions/xsl-array.md
create mode 100644 site/content/xslt/functions/xsl-attribute-set.md
create mode 100644 site/content/xslt/functions/xsl-attribute.md
create mode 100644 site/content/xslt/functions/xsl-break.md
create mode 100644 site/content/xslt/functions/xsl-call-template.md
create mode 100644 site/content/xslt/functions/xsl-catch.md
create mode 100644 site/content/xslt/functions/xsl-character-map.md
create mode 100644 site/content/xslt/functions/xsl-choose.md
create mode 100644 site/content/xslt/functions/xsl-comment.md
create mode 100644 site/content/xslt/functions/xsl-copy-of.md
create mode 100644 site/content/xslt/functions/xsl-copy.md
create mode 100644 site/content/xslt/functions/xsl-decimal-format.md
create mode 100644 site/content/xslt/functions/xsl-element.md
create mode 100644 site/content/xslt/functions/xsl-expose.md
create mode 100644 site/content/xslt/functions/xsl-fallback.md
create mode 100644 site/content/xslt/functions/xsl-fork.md
create mode 100644 site/content/xslt/functions/xsl-if.md
create mode 100644 site/content/xslt/functions/xsl-import-schema.md
create mode 100644 site/content/xslt/functions/xsl-import.md
create mode 100644 site/content/xslt/functions/xsl-include.md
create mode 100644 site/content/xslt/functions/xsl-key.md
create mode 100644 site/content/xslt/functions/xsl-map-entry.md
create mode 100644 site/content/xslt/functions/xsl-map.md
create mode 100644 site/content/xslt/functions/xsl-matching-substring.md
create mode 100644 site/content/xslt/functions/xsl-merge-action.md
create mode 100644 site/content/xslt/functions/xsl-merge-key.md
create mode 100644 site/content/xslt/functions/xsl-merge-source.md
create mode 100644 site/content/xslt/functions/xsl-merge.md
create mode 100644 site/content/xslt/functions/xsl-message.md
create mode 100644 site/content/xslt/functions/xsl-mode.md
create mode 100644 site/content/xslt/functions/xsl-namespace-alias.md
create mode 100644 site/content/xslt/functions/xsl-namespace.md
create mode 100644 site/content/xslt/functions/xsl-next-iteration.md
create mode 100644 site/content/xslt/functions/xsl-next-match.md
create mode 100644 site/content/xslt/functions/xsl-non-matching-substring.md
create mode 100644 site/content/xslt/functions/xsl-number.md
create mode 100644 site/content/xslt/functions/xsl-on-empty.md
create mode 100644 site/content/xslt/functions/xsl-on-non-empty.md
create mode 100644 site/content/xslt/functions/xsl-otherwise.md
create mode 100644 site/content/xslt/functions/xsl-output-character.md
create mode 100644 site/content/xslt/functions/xsl-output.md
create mode 100644 site/content/xslt/functions/xsl-override.md
create mode 100644 site/content/xslt/functions/xsl-package.md
create mode 100644 site/content/xslt/functions/xsl-param.md
create mode 100644 site/content/xslt/functions/xsl-perform-sort.md
create mode 100644 site/content/xslt/functions/xsl-preserve-space.md
create mode 100644 site/content/xslt/functions/xsl-processing-instruction.md
create mode 100644 site/content/xslt/functions/xsl-result-document.md
create mode 100644 site/content/xslt/functions/xsl-sequence.md
create mode 100644 site/content/xslt/functions/xsl-sort.md
create mode 100644 site/content/xslt/functions/xsl-stream.md
create mode 100644 site/content/xslt/functions/xsl-strip-space.md
create mode 100644 site/content/xslt/functions/xsl-stylesheet.md
create mode 100644 site/content/xslt/functions/xsl-template.md
create mode 100644 site/content/xslt/functions/xsl-text.md
create mode 100644 site/content/xslt/functions/xsl-transform.md
create mode 100644 site/content/xslt/functions/xsl-try.md
create mode 100644 site/content/xslt/functions/xsl-use-accumulators.md
create mode 100644 site/content/xslt/functions/xsl-use-package.md
create mode 100644 site/content/xslt/functions/xsl-variable.md
create mode 100644 site/content/xslt/functions/xsl-when.md
create mode 100644 site/content/xslt/functions/xsl-where-populated.md
create mode 100644 site/content/xslt/functions/xsl-with-param.md
diff --git a/frontend/src/lib/xsltCompletions.js b/frontend/src/lib/xsltCompletions.js
index 27c53c4d..5263bd37 100644
--- a/frontend/src/lib/xsltCompletions.js
+++ b/frontend/src/lib/xsltCompletions.js
@@ -9,83 +9,83 @@
export const XSL_ELEMENTS = [
// 1.0
- { label: "xsl:stylesheet", minVersion: "1.0", info: "Root element of an XSLT stylesheet", args: 'version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"' },
- { label: "xsl:transform", minVersion: "1.0", info: "Synonym for xsl:stylesheet", args: 'version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"' },
- { label: "xsl:template", minVersion: "1.0", info: "Defines a reusable template rule", args: 'match="/"' },
- { label: "xsl:apply-templates", minVersion: "1.0", info: "Applies templates to child nodes", args: 'select="node()"' },
- { label: "xsl:call-template", minVersion: "1.0", info: "Calls a named template", args: 'name="templateName"' },
+ { label: "xsl:stylesheet", minVersion: "1.0", info: "Root element of an XSLT stylesheet", args: 'version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"', blogSlug: "xsl-stylesheet" },
+ { label: "xsl:transform", minVersion: "1.0", info: "Synonym for xsl:stylesheet", args: 'version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"', blogSlug: "xsl-transform" },
+ { label: "xsl:template", minVersion: "1.0", info: "Defines a reusable template rule", args: 'match="/"', blogSlug: "xsl-template" },
+ { label: "xsl:apply-templates", minVersion: "1.0", info: "Applies templates to child nodes", args: 'select="node()"', blogSlug: "xsl-apply-templates" },
+ { label: "xsl:call-template", minVersion: "1.0", info: "Calls a named template", args: 'name="templateName"', blogSlug: "xsl-call-template" },
{ label: "xsl:value-of", minVersion: "1.0", info: "Outputs the string value of an XPath expression", args: 'select="."', blogSlug: "xsl-value-of" },
{ label: "xsl:for-each", minVersion: "1.0", info: "Iterates over a node-set", args: 'select="items/item"', blogSlug: "xsl-for-each" },
- { label: "xsl:if", minVersion: "1.0", info: "Conditional output", args: 'test="condition"' },
- { label: "xsl:choose", minVersion: "1.0", info: "Switch-like conditional block (use with xsl:when / xsl:otherwise)" },
- { label: "xsl:when", minVersion: "1.0", info: "Condition branch inside xsl:choose", args: 'test="condition"' },
- { label: "xsl:otherwise", minVersion: "1.0", info: "Default branch inside xsl:choose" },
- { label: "xsl:variable", minVersion: "1.0", info: "Declares a variable", args: 'name="varName" select="."' },
- { label: "xsl:param", minVersion: "1.0", info: "Declares a parameter (template or stylesheet level)", args: 'name="paramName"' },
- { label: "xsl:with-param", minVersion: "1.0", info: "Passes a parameter to a template", args: 'name="paramName" select="."' },
- { label: "xsl:sort", minVersion: "1.0", info: "Sorts nodes inside xsl:for-each or xsl:apply-templates", args: 'select="." order="ascending"' },
- { label: "xsl:copy", minVersion: "1.0", info: "Shallow-copies the current node" },
- { label: "xsl:copy-of", minVersion: "1.0", info: "Deep-copies a node-set or value", args: 'select="."' },
- { label: "xsl:text", minVersion: "1.0", info: "Outputs literal text (preserves whitespace)" },
- { label: "xsl:element", minVersion: "1.0", info: "Creates an element with a computed name", args: 'name="elementName"' },
- { label: "xsl:attribute", minVersion: "1.0", info: "Creates an attribute on the parent element", args: 'name="attrName"' },
- { label: "xsl:attribute-set", minVersion: "1.0", info: "Defines a named set of attributes", args: 'name="setName"' },
- { label: "xsl:comment", minVersion: "1.0", info: "Outputs an XML comment" },
- { label: "xsl:processing-instruction", minVersion: "1.0", info: "Outputs a processing instruction", args: 'name="piName"' },
- { label: "xsl:include", minVersion: "1.0", info: "Includes another stylesheet", args: 'href="other.xsl"' },
- { label: "xsl:import", minVersion: "1.0", info: "Imports another stylesheet (lower precedence)", args: 'href="other.xsl"' },
- { label: "xsl:output", minVersion: "1.0", info: "Controls serialization of the result tree", args: 'method="xml" indent="yes"' },
- { label: "xsl:preserve-space", minVersion: "1.0", info: "Preserves whitespace in specified elements", args: 'elements="*"' },
- { label: "xsl:strip-space", minVersion: "1.0", info: "Strips whitespace from specified elements", args: 'elements="*"' },
- { label: "xsl:key", minVersion: "1.0", info: "Defines an index key for the key() function", args: 'name="keyName" match="element" use="@id"' },
- { label: "xsl:decimal-format", minVersion: "1.0", info: "Defines a decimal format for format-number()" },
- { label: "xsl:namespace-alias", minVersion: "1.0", info: "Maps a namespace prefix to another", args: 'stylesheet-prefix="xsl" result-prefix="out"' },
- { label: "xsl:number", minVersion: "1.0", info: "Formats a number or generates a sequence number", args: 'value="position()"' },
- { label: "xsl:message", minVersion: "1.0", info: "Emits a diagnostic message (may terminate)", args: 'terminate="no"' },
- { label: "xsl:fallback", minVersion: "1.0", info: "Fallback content for unrecognized extension elements" },
+ { label: "xsl:if", minVersion: "1.0", info: "Conditional output", args: 'test="condition"', blogSlug: "xsl-if" },
+ { label: "xsl:choose", minVersion: "1.0", info: "Switch-like conditional block (use with xsl:when / xsl:otherwise)", blogSlug: "xsl-choose" },
+ { label: "xsl:when", minVersion: "1.0", info: "Condition branch inside xsl:choose", args: 'test="condition"', blogSlug: "xsl-when" },
+ { label: "xsl:otherwise", minVersion: "1.0", info: "Default branch inside xsl:choose", blogSlug: "xsl-otherwise" },
+ { label: "xsl:variable", minVersion: "1.0", info: "Declares a variable", args: 'name="varName" select="."', blogSlug: "xsl-variable" },
+ { label: "xsl:param", minVersion: "1.0", info: "Declares a parameter (template or stylesheet level)", args: 'name="paramName"', blogSlug: "xsl-param" },
+ { label: "xsl:with-param", minVersion: "1.0", info: "Passes a parameter to a template", args: 'name="paramName" select="."', blogSlug: "xsl-with-param" },
+ { label: "xsl:sort", minVersion: "1.0", info: "Sorts nodes inside xsl:for-each or xsl:apply-templates", args: 'select="." order="ascending"', blogSlug: "xsl-sort" },
+ { label: "xsl:copy", minVersion: "1.0", info: "Shallow-copies the current node", blogSlug: "xsl-copy" },
+ { label: "xsl:copy-of", minVersion: "1.0", info: "Deep-copies a node-set or value", args: 'select="."', blogSlug: "xsl-copy-of" },
+ { label: "xsl:text", minVersion: "1.0", info: "Outputs literal text (preserves whitespace)", blogSlug: "xsl-text" },
+ { label: "xsl:element", minVersion: "1.0", info: "Creates an element with a computed name", args: 'name="elementName"', blogSlug: "xsl-element" },
+ { label: "xsl:attribute", minVersion: "1.0", info: "Creates an attribute on the parent element", args: 'name="attrName"', blogSlug: "xsl-attribute" },
+ { label: "xsl:attribute-set", minVersion: "1.0", info: "Defines a named set of attributes", args: 'name="setName"', blogSlug: "xsl-attribute-set" },
+ { label: "xsl:comment", minVersion: "1.0", info: "Outputs an XML comment", blogSlug: "xsl-comment" },
+ { label: "xsl:processing-instruction", minVersion: "1.0", info: "Outputs a processing instruction", args: 'name="piName"', blogSlug: "xsl-processing-instruction" },
+ { label: "xsl:include", minVersion: "1.0", info: "Includes another stylesheet", args: 'href="other.xsl"', blogSlug: "xsl-include" },
+ { label: "xsl:import", minVersion: "1.0", info: "Imports another stylesheet (lower precedence)", args: 'href="other.xsl"', blogSlug: "xsl-import" },
+ { label: "xsl:output", minVersion: "1.0", info: "Controls serialization of the result tree", args: 'method="xml" indent="yes"', blogSlug: "xsl-output" },
+ { label: "xsl:preserve-space", minVersion: "1.0", info: "Preserves whitespace in specified elements", args: 'elements="*"', blogSlug: "xsl-preserve-space" },
+ { label: "xsl:strip-space", minVersion: "1.0", info: "Strips whitespace from specified elements", args: 'elements="*"', blogSlug: "xsl-strip-space" },
+ { label: "xsl:key", minVersion: "1.0", info: "Defines an index key for the key() function", args: 'name="keyName" match="element" use="@id"', blogSlug: "xsl-key" },
+ { label: "xsl:decimal-format", minVersion: "1.0", info: "Defines a decimal format for format-number()", blogSlug: "xsl-decimal-format" },
+ { label: "xsl:namespace-alias", minVersion: "1.0", info: "Maps a namespace prefix to another", args: 'stylesheet-prefix="xsl" result-prefix="out"', blogSlug: "xsl-namespace-alias" },
+ { label: "xsl:number", minVersion: "1.0", info: "Formats a number or generates a sequence number", args: 'value="position()"', blogSlug: "xsl-number" },
+ { label: "xsl:message", minVersion: "1.0", info: "Emits a diagnostic message (may terminate)", args: 'terminate="no"', blogSlug: "xsl-message" },
+ { label: "xsl:fallback", minVersion: "1.0", info: "Fallback content for unrecognized extension elements", blogSlug: "xsl-fallback" },
// 2.0
{ label: "xsl:function", minVersion: "2.0", info: "Defines a stylesheet function callable from XPath", args: 'name="my:func" as="xs:string"', blogSlug: "xsl-function" },
- { label: "xsl:sequence", minVersion: "2.0", info: "Returns a sequence of items", args: 'select="()"' },
- { label: "xsl:next-match", minVersion: "2.0", info: "Applies the next-matching template rule" },
- { label: "xsl:perform-sort", minVersion: "2.0", info: "Sorts a sequence without iteration", args: 'select="items"' },
+ { label: "xsl:sequence", minVersion: "2.0", info: "Returns a sequence of items", args: 'select="()"', blogSlug: "xsl-sequence" },
+ { label: "xsl:next-match", minVersion: "2.0", info: "Applies the next-matching template rule", blogSlug: "xsl-next-match" },
+ { label: "xsl:perform-sort", minVersion: "2.0", info: "Sorts a sequence without iteration", args: 'select="items"', blogSlug: "xsl-perform-sort" },
{ label: "xsl:for-each-group", minVersion: "2.0", info: "Groups items in a sequence", args: 'select="items" group-by="."', blogSlug: "xsl-for-each-group" },
- { label: "xsl:analyze-string", minVersion: "2.0", info: "Processes a string against a regex", args: 'select="." regex="pattern"' },
- { label: "xsl:matching-substring", minVersion: "2.0", info: "Content within xsl:analyze-string for matching parts" },
- { label: "xsl:non-matching-substring", minVersion: "2.0", info: "Content within xsl:analyze-string for non-matching parts" },
- { label: "xsl:namespace", minVersion: "2.0", info: "Creates a namespace node", args: 'name="prefix"' },
- { label: "xsl:character-map", minVersion: "2.0", info: "Maps characters to strings during serialization", args: 'name="mapName"' },
- { label: "xsl:output-character", minVersion: "2.0", info: "Maps a single character inside xsl:character-map", args: 'character="&" string="&"' },
- { label: "xsl:import-schema", minVersion: "2.0", info: "Imports an XML Schema for type-aware processing", args: 'namespace="http://example.com"' },
- { label: "xsl:result-document", minVersion: "2.0", info: "Writes output to a secondary result document", args: 'href="output.xml" method="xml"' },
+ { label: "xsl:analyze-string", minVersion: "2.0", info: "Processes a string against a regex", args: 'select="." regex="pattern"', blogSlug: "xsl-analyze-string" },
+ { label: "xsl:matching-substring", minVersion: "2.0", info: "Content within xsl:analyze-string for matching parts", blogSlug: "xsl-matching-substring" },
+ { label: "xsl:non-matching-substring", minVersion: "2.0", info: "Content within xsl:analyze-string for non-matching parts", blogSlug: "xsl-non-matching-substring" },
+ { label: "xsl:namespace", minVersion: "2.0", info: "Creates a namespace node", args: 'name="prefix"', blogSlug: "xsl-namespace" },
+ { label: "xsl:character-map", minVersion: "2.0", info: "Maps characters to strings during serialization", args: 'name="mapName"', blogSlug: "xsl-character-map" },
+ { label: "xsl:output-character", minVersion: "2.0", info: "Maps a single character inside xsl:character-map", args: 'character="&" string="&"', blogSlug: "xsl-output-character" },
+ { label: "xsl:import-schema", minVersion: "2.0", info: "Imports an XML Schema for type-aware processing", args: 'namespace="http://example.com"', blogSlug: "xsl-import-schema" },
+ { label: "xsl:result-document", minVersion: "2.0", info: "Writes output to a secondary result document", args: 'href="output.xml" method="xml"', blogSlug: "xsl-result-document" },
// 3.0
- { label: "xsl:package", minVersion: "3.0", info: "Defines an XSLT 3.0 package", args: 'name="com.example.pkg" version="1.0"' },
- { label: "xsl:use-package", minVersion: "3.0", info: "Uses a compiled package", args: 'name="com.example.pkg"' },
- { label: "xsl:expose", minVersion: "3.0", info: "Controls visibility of components within a package", args: 'component="function" match="*" visibility="public"' },
- { label: "xsl:override", minVersion: "3.0", info: "Overrides components from a used package" },
- { label: "xsl:mode", minVersion: "3.0", info: "Declares a mode and its default behavior", args: 'name="modeName" on-no-match="shallow-copy"' },
- { label: "xsl:accept", minVersion: "3.0", info: "Accepts components from a used package", args: 'component="function" match="*" visibility="public"' },
- { label: "xsl:try", minVersion: "3.0", info: "Attempts an expression; catches errors", args: 'select="expression"' },
- { label: "xsl:catch", minVersion: "3.0", info: "Catches errors from xsl:try" },
- { label: "xsl:on-empty", minVersion: "3.0", info: "Content to output when the sequence is empty" },
- { label: "xsl:on-non-empty", minVersion: "3.0", info: "Content to output when the sequence is non-empty" },
- { label: "xsl:where-populated", minVersion: "3.0", info: "Suppresses output if the content would be empty" },
- { label: "xsl:map", minVersion: "3.0", info: "Creates an XPath 3.1 map", args: '' },
- { label: "xsl:map-entry", minVersion: "3.0", info: "Creates a key-value entry inside xsl:map", args: 'key="." select="."' },
- { label: "xsl:array", minVersion: "3.0", info: "Creates an XPath 3.1 array" },
- { label: "xsl:array-member", minVersion: "3.0", info: "Creates a member inside xsl:array", args: 'select="."' },
- { label: "xsl:stream", minVersion: "3.0", info: "Processes a document in streaming mode", args: 'href="large.xml"' },
+ { label: "xsl:package", minVersion: "3.0", info: "Defines an XSLT 3.0 package", args: 'name="com.example.pkg" version="1.0"', blogSlug: "xsl-package" },
+ { label: "xsl:use-package", minVersion: "3.0", info: "Uses a compiled package", args: 'name="com.example.pkg"', blogSlug: "xsl-use-package" },
+ { label: "xsl:expose", minVersion: "3.0", info: "Controls visibility of components within a package", args: 'component="function" match="*" visibility="public"', blogSlug: "xsl-expose" },
+ { label: "xsl:override", minVersion: "3.0", info: "Overrides components from a used package", blogSlug: "xsl-override" },
+ { label: "xsl:mode", minVersion: "3.0", info: "Declares a mode and its default behavior", args: 'name="modeName" on-no-match="shallow-copy"', blogSlug: "xsl-mode" },
+ { label: "xsl:accept", minVersion: "3.0", info: "Accepts components from a used package", args: 'component="function" match="*" visibility="public"', blogSlug: "xsl-accept" },
+ { label: "xsl:try", minVersion: "3.0", info: "Attempts an expression; catches errors", args: 'select="expression"', blogSlug: "xsl-try" },
+ { label: "xsl:catch", minVersion: "3.0", info: "Catches errors from xsl:try", blogSlug: "xsl-catch" },
+ { label: "xsl:on-empty", minVersion: "3.0", info: "Content to output when the sequence is empty", blogSlug: "xsl-on-empty" },
+ { label: "xsl:on-non-empty", minVersion: "3.0", info: "Content to output when the sequence is non-empty", blogSlug: "xsl-on-non-empty" },
+ { label: "xsl:where-populated", minVersion: "3.0", info: "Suppresses output if the content would be empty", blogSlug: "xsl-where-populated" },
+ { label: "xsl:map", minVersion: "3.0", info: "Creates an XPath 3.1 map", args: '', blogSlug: "xsl-map" },
+ { label: "xsl:map-entry", minVersion: "3.0", info: "Creates a key-value entry inside xsl:map", args: 'key="." select="."', blogSlug: "xsl-map-entry" },
+ { label: "xsl:array", minVersion: "3.0", info: "Creates an XPath 3.1 array", blogSlug: "xsl-array" },
+ { label: "xsl:array-member", minVersion: "3.0", info: "Creates a member inside xsl:array", args: 'select="."', blogSlug: "xsl-array-member" },
+ { label: "xsl:stream", minVersion: "3.0", info: "Processes a document in streaming mode", args: 'href="large.xml"', blogSlug: "xsl-stream" },
{ label: "xsl:iterate", minVersion: "3.0", info: "Iterates with carry-over accumulators", args: 'select="items"', blogSlug: "xsl-iterate" },
{ label: "xsl:param", minVersion: "3.0", info: "Streaming: parameter inside xsl:iterate" }, // duplicate intentional (context differs)
- { label: "xsl:break", minVersion: "3.0", info: "Exits xsl:iterate early", args: 'select="."' },
- { label: "xsl:next-iteration", minVersion: "3.0", info: "Continues xsl:iterate with updated parameters" },
- { label: "xsl:fork", minVersion: "3.0", info: "Processes a sequence in multiple streams simultaneously" },
- { label: "xsl:merge", minVersion: "3.0", info: "Merges pre-sorted sequences", args: '' },
- { label: "xsl:merge-source", minVersion: "3.0", info: "Defines one source for xsl:merge", args: 'name="src" select="collection()"' },
- { label: "xsl:merge-key", minVersion: "3.0", info: "Defines the merge key inside xsl:merge-source", args: 'select="." order="ascending"' },
- { label: "xsl:merge-action", minVersion: "3.0", info: "Body executed for each group of merged items" },
- { label: "xsl:accumulator", minVersion: "3.0", info: "Defines a streaming accumulator", args: 'name="acc" initial-value="0"' },
- { label: "xsl:accumulator-rule", minVersion: "3.0", info: "Rule inside xsl:accumulator", args: 'match="element"' },
- { label: "xsl:use-accumulators", minVersion: "3.0", info: "Declares which accumulators are used in a template" },
+ { label: "xsl:break", minVersion: "3.0", info: "Exits xsl:iterate early", args: 'select="."', blogSlug: "xsl-break" },
+ { label: "xsl:next-iteration", minVersion: "3.0", info: "Continues xsl:iterate with updated parameters", blogSlug: "xsl-next-iteration" },
+ { label: "xsl:fork", minVersion: "3.0", info: "Processes a sequence in multiple streams simultaneously", blogSlug: "xsl-fork" },
+ { label: "xsl:merge", minVersion: "3.0", info: "Merges pre-sorted sequences", args: '', blogSlug: "xsl-merge" },
+ { label: "xsl:merge-source", minVersion: "3.0", info: "Defines one source for xsl:merge", args: 'name="src" select="collection()"', blogSlug: "xsl-merge-source" },
+ { label: "xsl:merge-key", minVersion: "3.0", info: "Defines the merge key inside xsl:merge-source", args: 'select="." order="ascending"', blogSlug: "xsl-merge-key" },
+ { label: "xsl:merge-action", minVersion: "3.0", info: "Body executed for each group of merged items", blogSlug: "xsl-merge-action" },
+ { label: "xsl:accumulator", minVersion: "3.0", info: "Defines a streaming accumulator", args: 'name="acc" initial-value="0"', blogSlug: "xsl-accumulator" },
+ { label: "xsl:accumulator-rule", minVersion: "3.0", info: "Rule inside xsl:accumulator", args: 'match="element"', blogSlug: "xsl-accumulator-rule" },
+ { label: "xsl:use-accumulators", minVersion: "3.0", info: "Declares which accumulators are used in a template", blogSlug: "xsl-use-accumulators" },
];
// ─── XPath functions ─────────────────────────────────────────────────────────
@@ -95,173 +95,173 @@ export const XPATH_FUNCTIONS = [
{ label: "last()", minVersion: "1.0", info: "Returns the size of the context node-set", blogSlug: "xpath-last" },
{ label: "position()", minVersion: "1.0", info: "Returns the context position", blogSlug: "xpath-position" },
{ label: "count(node-set)", minVersion: "1.0", info: "Returns the number of nodes in a node-set", blogSlug: "xpath-count" },
- { label: "id(string)", minVersion: "1.0", info: "Selects elements by their unique ID attribute" },
- { label: "local-name(node?)", minVersion: "1.0", info: "Returns the local part of a node's name" },
- { label: "namespace-uri(node?)", minVersion: "1.0", info: "Returns the namespace URI of a node" },
- { label: "name(node?)", minVersion: "1.0", info: "Returns the qualified name of a node" },
+ { label: "id(string)", minVersion: "1.0", info: "Selects elements by their unique ID attribute", blogSlug: "xpath-id" },
+ { label: "local-name(node?)", minVersion: "1.0", info: "Returns the local part of a node's name", blogSlug: "xpath-local-name" },
+ { label: "namespace-uri(node?)", minVersion: "1.0", info: "Returns the namespace URI of a node", blogSlug: "xpath-namespace-uri" },
+ { label: "name(node?)", minVersion: "1.0", info: "Returns the qualified name of a node", blogSlug: "xpath-name" },
// 1.0 string
- { label: "string(object?)", minVersion: "1.0", info: "Converts an object to a string" },
+ { label: "string(object?)", minVersion: "1.0", info: "Converts an object to a string", blogSlug: "xpath-string" },
{ label: "concat(str, str, ...)", minVersion: "1.0", info: "Concatenates two or more strings", blogSlug: "xpath-concat" },
- { label: "starts-with(str, prefix)", minVersion: "1.0", info: "Returns true if str starts with prefix" },
+ { label: "starts-with(str, prefix)", minVersion: "1.0", info: "Returns true if str starts with prefix", blogSlug: "xpath-starts-with" },
{ label: "contains(str, substr)", minVersion: "1.0", info: "Returns true if str contains substr", blogSlug: "xpath-contains" },
- { label: "substring-before(str, sep)", minVersion: "1.0", info: "Returns the part of str before the first sep" },
- { label: "substring-after(str, sep)", minVersion: "1.0", info: "Returns the part of str after the first sep" },
+ { label: "substring-before(str, sep)", minVersion: "1.0", info: "Returns the part of str before the first sep", blogSlug: "xpath-substring-before" },
+ { label: "substring-after(str, sep)", minVersion: "1.0", info: "Returns the part of str after the first sep", blogSlug: "xpath-substring-after" },
{ label: "substring(str, start, len?)", minVersion: "1.0", info: "Returns a substring (1-based)", blogSlug: "xpath-substring" },
- { label: "string-length(str?)", minVersion: "1.0", info: "Returns the length of a string" },
- { label: "normalize-space(str?)", minVersion: "1.0", info: "Strips leading/trailing whitespace and collapses internal whitespace" },
- { label: "translate(str, from, to)", minVersion: "1.0", info: "Replaces characters in str: each char in from is replaced by the corresponding char in to" },
+ { label: "string-length(str?)", minVersion: "1.0", info: "Returns the length of a string", blogSlug: "xpath-string-length" },
+ { label: "normalize-space(str?)", minVersion: "1.0", info: "Strips leading/trailing whitespace and collapses internal whitespace", blogSlug: "xpath-normalize-space" },
+ { label: "translate(str, from, to)", minVersion: "1.0", info: "Replaces characters in str: each char in from is replaced by the corresponding char in to", blogSlug: "xpath-translate" },
// 1.0 boolean
- { label: "boolean(object)", minVersion: "1.0", info: "Converts an object to boolean" },
- { label: "not(boolean)", minVersion: "1.0", info: "Returns the boolean negation" },
- { label: "true()", minVersion: "1.0", info: "Returns true" },
- { label: "false()", minVersion: "1.0", info: "Returns false" },
- { label: "lang(string)", minVersion: "1.0", info: "Returns true if the context node's language matches" },
+ { label: "boolean(object)", minVersion: "1.0", info: "Converts an object to boolean", blogSlug: "xpath-boolean" },
+ { label: "not(boolean)", minVersion: "1.0", info: "Returns the boolean negation", blogSlug: "xpath-not" },
+ { label: "true()", minVersion: "1.0", info: "Returns true", blogSlug: "xpath-true" },
+ { label: "false()", minVersion: "1.0", info: "Returns false", blogSlug: "xpath-false" },
+ { label: "lang(string)", minVersion: "1.0", info: "Returns true if the context node's language matches", blogSlug: "xpath-lang" },
// 1.0 number
- { label: "number(object?)", minVersion: "1.0", info: "Converts an object to a number" },
+ { label: "number(object?)", minVersion: "1.0", info: "Converts an object to a number", blogSlug: "xpath-number" },
{ label: "sum(node-set)", minVersion: "1.0", info: "Returns the sum of numeric values in a node-set", blogSlug: "xpath-sum" },
- { label: "floor(number)", minVersion: "1.0", info: "Rounds down to the nearest integer" },
- { label: "ceiling(number)", minVersion: "1.0", info: "Rounds up to the nearest integer" },
- { label: "round(number)", minVersion: "1.0", info: "Rounds to the nearest integer" },
+ { label: "floor(number)", minVersion: "1.0", info: "Rounds down to the nearest integer", blogSlug: "xpath-floor" },
+ { label: "ceiling(number)", minVersion: "1.0", info: "Rounds up to the nearest integer", blogSlug: "xpath-ceiling" },
+ { label: "round(number)", minVersion: "1.0", info: "Rounds to the nearest integer", blogSlug: "xpath-round" },
// XSLT 1.0 extra
{ label: "key(name, value)", minVersion: "1.0", info: "Looks up nodes using a key defined with xsl:key", blogSlug: "xpath-key" },
- { label: "format-number(num, pattern, decimalFormat?)", minVersion: "1.0", info: "Formats a number using a decimal format pattern" },
+ { label: "format-number(num, pattern, decimalFormat?)", minVersion: "1.0", info: "Formats a number using a decimal format pattern", blogSlug: "xpath-format-number" },
{ label: "current()", minVersion: "1.0", info: "Returns the current node (differs from . inside predicates)", blogSlug: "xpath-current" },
- { label: "document(uri, node?)", minVersion: "1.0", info: "Loads an external XML document" },
- { label: "unparsed-entity-uri(name)", minVersion: "1.0", info: "Returns the URI of an unparsed entity" },
- { label: "generate-id(node?)", minVersion: "1.0", info: "Generates a unique string ID for a node" },
- { label: "system-property(name)", minVersion: "1.0", info: "Returns XSLT system properties (xsl:version, xsl:vendor, ...)" },
- { label: "element-available(name)", minVersion: "1.0", info: "Returns true if the element is available" },
- { label: "function-available(name)", minVersion: "1.0", info: "Returns true if the function is available" },
+ { label: "document(uri, node?)", minVersion: "1.0", info: "Loads an external XML document", blogSlug: "xpath-document" },
+ { label: "unparsed-entity-uri(name)", minVersion: "1.0", info: "Returns the URI of an unparsed entity", blogSlug: "xpath-unparsed-entity-uri" },
+ { label: "generate-id(node?)", minVersion: "1.0", info: "Generates a unique string ID for a node", blogSlug: "xpath-generate-id" },
+ { label: "system-property(name)", minVersion: "1.0", info: "Returns XSLT system properties (xsl:version, xsl:vendor, ...)", blogSlug: "xpath-system-property" },
+ { label: "element-available(name)", minVersion: "1.0", info: "Returns true if the element is available", blogSlug: "xpath-element-available" },
+ { label: "function-available(name)", minVersion: "1.0", info: "Returns true if the function is available", blogSlug: "xpath-function-available" },
// 2.0 string
{ label: "string-join(seq, sep?)", minVersion: "2.0", info: "Joins a sequence of strings with a separator", blogSlug: "xpath-string-join" },
{ label: "tokenize(str, pattern)", minVersion: "2.0", info: "Splits a string by a regex pattern", blogSlug: "xpath-tokenize" },
{ label: "matches(str, pattern, flags?)", minVersion: "2.0", info: "Returns true if str matches a regex", blogSlug: "xpath-matches" },
{ label: "replace(str, pattern, replacement, flags?)", minVersion: "2.0", info: "Replaces regex matches in a string", blogSlug: "xpath-replace" },
- { label: "upper-case(str)", minVersion: "2.0", info: "Converts a string to uppercase" },
- { label: "lower-case(str)", minVersion: "2.0", info: "Converts a string to lowercase" },
- { label: "ends-with(str, suffix)", minVersion: "2.0", info: "Returns true if str ends with suffix" },
- { label: "codepoints-to-string(seq)", minVersion: "2.0", info: "Converts Unicode codepoints to a string" },
- { label: "string-to-codepoints(str)", minVersion: "2.0", info: "Converts a string to a sequence of Unicode codepoints" },
- { label: "compare(str1, str2, collation?)", minVersion: "2.0", info: "Compares two strings, returns -1, 0 or 1" },
- { label: "normalize-unicode(str, form?)", minVersion: "2.0", info: "Normalizes a string to a Unicode normalization form" },
+ { label: "upper-case(str)", minVersion: "2.0", info: "Converts a string to uppercase", blogSlug: "xpath-upper-case" },
+ { label: "lower-case(str)", minVersion: "2.0", info: "Converts a string to lowercase", blogSlug: "xpath-lower-case" },
+ { label: "ends-with(str, suffix)", minVersion: "2.0", info: "Returns true if str ends with suffix", blogSlug: "xpath-ends-with" },
+ { label: "codepoints-to-string(seq)", minVersion: "2.0", info: "Converts Unicode codepoints to a string", blogSlug: "xpath-codepoints-to-string" },
+ { label: "string-to-codepoints(str)", minVersion: "2.0", info: "Converts a string to a sequence of Unicode codepoints", blogSlug: "xpath-string-to-codepoints" },
+ { label: "compare(str1, str2, collation?)", minVersion: "2.0", info: "Compares two strings, returns -1, 0 or 1", blogSlug: "xpath-compare" },
+ { label: "normalize-unicode(str, form?)", minVersion: "2.0", info: "Normalizes a string to a Unicode normalization form", blogSlug: "xpath-normalize-unicode" },
// 2.0 sequence
- { label: "empty(seq)", minVersion: "2.0", info: "Returns true if the sequence is empty" },
- { label: "exists(seq)", minVersion: "2.0", info: "Returns true if the sequence is non-empty" },
- { label: "distinct-values(seq, collation?)", minVersion: "2.0", info: "Returns distinct values from a sequence" },
- { label: "insert-before(seq, pos, ins)", minVersion: "2.0", info: "Inserts items into a sequence at a position" },
- { label: "remove(seq, pos)", minVersion: "2.0", info: "Removes an item at a position from a sequence" },
- { label: "reverse(seq)", minVersion: "2.0", info: "Reverses a sequence" },
- { label: "subsequence(seq, start, len?)", minVersion: "2.0", info: "Returns a subsequence" },
- { label: "unordered(seq)", minVersion: "2.0", info: "Returns items in implementation-defined order (hint to optimizer)" },
- { label: "index-of(seq, value, collation?)", minVersion: "2.0", info: "Returns positions of a value in a sequence" },
- { label: "deep-equal(seq1, seq2, collation?)", minVersion: "2.0", info: "Returns true if two sequences are deeply equal" },
- { label: "zero-or-one(seq)", minVersion: "2.0", info: "Asserts the sequence has 0 or 1 items" },
- { label: "exactly-one(seq)", minVersion: "2.0", info: "Asserts the sequence has exactly 1 item" },
- { label: "one-or-more(seq)", minVersion: "2.0", info: "Asserts the sequence has 1 or more items" },
+ { label: "empty(seq)", minVersion: "2.0", info: "Returns true if the sequence is empty", blogSlug: "xpath-empty" },
+ { label: "exists(seq)", minVersion: "2.0", info: "Returns true if the sequence is non-empty", blogSlug: "xpath-exists" },
+ { label: "distinct-values(seq, collation?)", minVersion: "2.0", info: "Returns distinct values from a sequence", blogSlug: "xpath-distinct-values" },
+ { label: "insert-before(seq, pos, ins)", minVersion: "2.0", info: "Inserts items into a sequence at a position", blogSlug: "xpath-insert-before" },
+ { label: "remove(seq, pos)", minVersion: "2.0", info: "Removes an item at a position from a sequence", blogSlug: "xpath-remove" },
+ { label: "reverse(seq)", minVersion: "2.0", info: "Reverses a sequence", blogSlug: "xpath-reverse" },
+ { label: "subsequence(seq, start, len?)", minVersion: "2.0", info: "Returns a subsequence", blogSlug: "xpath-subsequence" },
+ { label: "unordered(seq)", minVersion: "2.0", info: "Returns items in implementation-defined order (hint to optimizer)", blogSlug: "xpath-unordered" },
+ { label: "index-of(seq, value, collation?)", minVersion: "2.0", info: "Returns positions of a value in a sequence", blogSlug: "xpath-index-of" },
+ { label: "deep-equal(seq1, seq2, collation?)", minVersion: "2.0", info: "Returns true if two sequences are deeply equal", blogSlug: "xpath-deep-equal" },
+ { label: "zero-or-one(seq)", minVersion: "2.0", info: "Asserts the sequence has 0 or 1 items", blogSlug: "xpath-zero-or-one" },
+ { label: "exactly-one(seq)", minVersion: "2.0", info: "Asserts the sequence has exactly 1 item", blogSlug: "xpath-exactly-one" },
+ { label: "one-or-more(seq)", minVersion: "2.0", info: "Asserts the sequence has 1 or more items", blogSlug: "xpath-one-or-more" },
// 2.0 numeric
- { label: "abs(number)", minVersion: "2.0", info: "Returns the absolute value" },
- { label: "min(seq, collation?)", minVersion: "2.0", info: "Returns the minimum value in a sequence" },
- { label: "max(seq, collation?)", minVersion: "2.0", info: "Returns the maximum value in a sequence" },
- { label: "avg(seq)", minVersion: "2.0", info: "Returns the average of a sequence of numeric values" },
+ { label: "abs(number)", minVersion: "2.0", info: "Returns the absolute value", blogSlug: "xpath-abs" },
+ { label: "min(seq, collation?)", minVersion: "2.0", info: "Returns the minimum value in a sequence", blogSlug: "xpath-min" },
+ { label: "max(seq, collation?)", minVersion: "2.0", info: "Returns the maximum value in a sequence", blogSlug: "xpath-max" },
+ { label: "avg(seq)", minVersion: "2.0", info: "Returns the average of a sequence of numeric values", blogSlug: "xpath-avg" },
// 2.0 date/time
- { label: "current-date()", minVersion: "2.0", info: "Returns today's date as xs:date" },
- { label: "current-time()", minVersion: "2.0", info: "Returns current time as xs:time" },
- { label: "current-dateTime()", minVersion: "2.0", info: "Returns current date+time as xs:dateTime" },
- { label: "year-from-date(date)", minVersion: "2.0", info: "Extracts the year from an xs:date" },
- { label: "month-from-date(date)", minVersion: "2.0", info: "Extracts the month from an xs:date" },
- { label: "day-from-date(date)", minVersion: "2.0", info: "Extracts the day from an xs:date" },
- { label: "hours-from-time(time)", minVersion: "2.0", info: "Extracts hours from xs:time" },
- { label: "minutes-from-time(time)", minVersion: "2.0", info: "Extracts minutes from xs:time" },
- { label: "seconds-from-time(time)", minVersion: "2.0", info: "Extracts seconds from xs:time" },
+ { label: "current-date()", minVersion: "2.0", info: "Returns today's date as xs:date", blogSlug: "xpath-current-date" },
+ { label: "current-time()", minVersion: "2.0", info: "Returns current time as xs:time", blogSlug: "xpath-current-time" },
+ { label: "current-dateTime()", minVersion: "2.0", info: "Returns current date+time as xs:dateTime", blogSlug: "xpath-current-date-time" },
+ { label: "year-from-date(date)", minVersion: "2.0", info: "Extracts the year from an xs:date", blogSlug: "xpath-year-from-date" },
+ { label: "month-from-date(date)", minVersion: "2.0", info: "Extracts the month from an xs:date", blogSlug: "xpath-month-from-date" },
+ { label: "day-from-date(date)", minVersion: "2.0", info: "Extracts the day from an xs:date", blogSlug: "xpath-day-from-date" },
+ { label: "hours-from-time(time)", minVersion: "2.0", info: "Extracts hours from xs:time", blogSlug: "xpath-hours-from-time" },
+ { label: "minutes-from-time(time)", minVersion: "2.0", info: "Extracts minutes from xs:time", blogSlug: "xpath-minutes-from-time" },
+ { label: "seconds-from-time(time)", minVersion: "2.0", info: "Extracts seconds from xs:time", blogSlug: "xpath-seconds-from-time" },
{ label: "format-date(date, picture, lang?, calendar?, place?)", minVersion: "2.0", info: "Formats an xs:date using a picture string", blogSlug: "xpath-format-date" },
- { label: "format-time(time, picture, lang?, calendar?, place?)", minVersion: "2.0", info: "Formats an xs:time using a picture string" },
- { label: "format-dateTime(dateTime, picture, lang?, calendar?, place?)", minVersion: "2.0", info: "Formats an xs:dateTime using a picture string" },
+ { label: "format-time(time, picture, lang?, calendar?, place?)", minVersion: "2.0", info: "Formats an xs:time using a picture string", blogSlug: "xpath-format-time" },
+ { label: "format-dateTime(dateTime, picture, lang?, calendar?, place?)", minVersion: "2.0", info: "Formats an xs:dateTime using a picture string", blogSlug: "xpath-format-date-time" },
// 2.0 node
- { label: "base-uri(node?)", minVersion: "2.0", info: "Returns the base URI of a node" },
- { label: "document-uri(node?)", minVersion: "2.0", info: "Returns the URI of a document node" },
- { label: "nilled(node?)", minVersion: "2.0", info: "Returns true if a node is nilled" },
- { label: "node-name(node?)", minVersion: "2.0", info: "Returns the name of a node as xs:QName" },
+ { label: "base-uri(node?)", minVersion: "2.0", info: "Returns the base URI of a node", blogSlug: "xpath-base-uri" },
+ { label: "document-uri(node?)", minVersion: "2.0", info: "Returns the URI of a document node", blogSlug: "xpath-document-uri" },
+ { label: "nilled(node?)", minVersion: "2.0", info: "Returns true if a node is nilled", blogSlug: "xpath-nilled" },
+ { label: "node-name(node?)", minVersion: "2.0", info: "Returns the name of a node as xs:QName", blogSlug: "xpath-node-name" },
// 2.0 QName / misc
- { label: "QName(uri, name)", minVersion: "2.0", info: "Creates an xs:QName value" },
- { label: "local-name-from-QName(qname)", minVersion: "2.0", info: "Returns the local part of an xs:QName" },
- { label: "namespace-uri-from-QName(qname)", minVersion: "2.0", info: "Returns the namespace URI of an xs:QName" },
- { label: "prefix-from-QName(qname)", minVersion: "2.0", info: "Returns the prefix of an xs:QName" },
- { label: "resolve-QName(str, element)", minVersion: "2.0", info: "Resolves a lexical QName using in-scope namespaces" },
- { label: "error(qname?, desc?, obj?)", minVersion: "2.0", info: "Raises an error" },
- { label: "trace(value, label?)", minVersion: "2.0", info: "Emits a trace message and returns the value unchanged" },
- { label: "static-base-uri()", minVersion: "2.0", info: "Returns the static base URI of the stylesheet" },
- { label: "implicit-timezone()", minVersion: "2.0", info: "Returns the implicit timezone" },
+ { label: "QName(uri, name)", minVersion: "2.0", info: "Creates an xs:QName value", blogSlug: "xpath-qname" },
+ { label: "local-name-from-QName(qname)", minVersion: "2.0", info: "Returns the local part of an xs:QName", blogSlug: "xpath-local-name-from-qname" },
+ { label: "namespace-uri-from-QName(qname)", minVersion: "2.0", info: "Returns the namespace URI of an xs:QName", blogSlug: "xpath-namespace-uri-from-qname" },
+ { label: "prefix-from-QName(qname)", minVersion: "2.0", info: "Returns the prefix of an xs:QName", blogSlug: "xpath-prefix-from-qname" },
+ { label: "resolve-QName(str, element)", minVersion: "2.0", info: "Resolves a lexical QName using in-scope namespaces", blogSlug: "xpath-resolve-qname" },
+ { label: "error(qname?, desc?, obj?)", minVersion: "2.0", info: "Raises an error", blogSlug: "xpath-error" },
+ { label: "trace(value, label?)", minVersion: "2.0", info: "Emits a trace message and returns the value unchanged", blogSlug: "xpath-trace" },
+ { label: "static-base-uri()", minVersion: "2.0", info: "Returns the static base URI of the stylesheet", blogSlug: "xpath-static-base-uri" },
+ { label: "implicit-timezone()", minVersion: "2.0", info: "Returns the implicit timezone", blogSlug: "xpath-implicit-timezone" },
// 3.0 functional
- { label: "apply(func, args)", minVersion: "3.0", info: "Calls a function with an array of arguments" },
- { label: "function-lookup(name, arity)", minVersion: "3.0", info: "Returns a function by name and arity, or the empty sequence" },
- { label: "function-name(func)", minVersion: "3.0", info: "Returns the name of a function item" },
- { label: "function-arity(func)", minVersion: "3.0", info: "Returns the arity of a function item" },
- { label: "for-each(seq, func)", minVersion: "3.0", info: "Applies a function to each item of a sequence" },
- { label: "filter(seq, func)", minVersion: "3.0", info: "Filters a sequence by a predicate function" },
- { label: "fold-left(seq, zero, func)", minVersion: "3.0", info: "Left-fold: accumulates a result over a sequence" },
- { label: "fold-right(seq, zero, func)", minVersion: "3.0", info: "Right-fold: accumulates a result over a sequence (from the right)" },
- { label: "for-each-pair(seq1, seq2, func)", minVersion: "3.0", info: "Applies a function to pairs of items from two sequences" },
- { label: "sort(seq, collation?, key?)", minVersion: "3.0", info: "Sorts a sequence (functional alternative to xsl:sort)" },
- { label: "random-number-generator(seed?)", minVersion: "3.0", info: "Returns a random number generator map" },
+ { label: "apply(func, args)", minVersion: "3.0", info: "Calls a function with an array of arguments", blogSlug: "xpath-apply" },
+ { label: "function-lookup(name, arity)", minVersion: "3.0", info: "Returns a function by name and arity, or the empty sequence", blogSlug: "xpath-function-lookup" },
+ { label: "function-name(func)", minVersion: "3.0", info: "Returns the name of a function item", blogSlug: "xpath-function-name" },
+ { label: "function-arity(func)", minVersion: "3.0", info: "Returns the arity of a function item", blogSlug: "xpath-function-arity" },
+ { label: "for-each(seq, func)", minVersion: "3.0", info: "Applies a function to each item of a sequence", blogSlug: "xpath-for-each" },
+ { label: "filter(seq, func)", minVersion: "3.0", info: "Filters a sequence by a predicate function", blogSlug: "xpath-filter" },
+ { label: "fold-left(seq, zero, func)", minVersion: "3.0", info: "Left-fold: accumulates a result over a sequence", blogSlug: "xpath-fold-left" },
+ { label: "fold-right(seq, zero, func)", minVersion: "3.0", info: "Right-fold: accumulates a result over a sequence (from the right)", blogSlug: "xpath-fold-right" },
+ { label: "for-each-pair(seq1, seq2, func)", minVersion: "3.0", info: "Applies a function to pairs of items from two sequences", blogSlug: "xpath-for-each-pair" },
+ { label: "sort(seq, collation?, key?)", minVersion: "3.0", info: "Sorts a sequence (functional alternative to xsl:sort)", blogSlug: "xpath-sort" },
+ { label: "random-number-generator(seed?)", minVersion: "3.0", info: "Returns a random number generator map", blogSlug: "xpath-random-number-generator" },
// 3.0 map
- { label: "map:merge(maps, options?)", minVersion: "3.0", info: "Merges multiple maps into one" },
- { label: "map:size(map)", minVersion: "3.0", info: "Returns the number of entries in a map" },
- { label: "map:keys(map)", minVersion: "3.0", info: "Returns the keys of a map as a sequence" },
- { label: "map:contains(map, key)", minVersion: "3.0", info: "Returns true if the map contains the key" },
- { label: "map:get(map, key)", minVersion: "3.0", info: "Returns the value for a key in a map, or the empty sequence" },
- { label: "map:put(map, key, value)", minVersion: "3.0", info: "Returns a new map with the key-value pair added or updated" },
- { label: "map:remove(map, keys)", minVersion: "3.0", info: "Returns a new map with specified keys removed" },
- { label: "map:entry(key, value)", minVersion: "3.0", info: "Creates a singleton map with one key-value entry" },
+ { label: "map:merge(maps, options?)", minVersion: "3.0", info: "Merges multiple maps into one", blogSlug: "xpath-map-merge" },
+ { label: "map:size(map)", minVersion: "3.0", info: "Returns the number of entries in a map", blogSlug: "xpath-map-size" },
+ { label: "map:keys(map)", minVersion: "3.0", info: "Returns the keys of a map as a sequence", blogSlug: "xpath-map-keys" },
+ { label: "map:contains(map, key)", minVersion: "3.0", info: "Returns true if the map contains the key", blogSlug: "xpath-map-contains" },
+ { label: "map:get(map, key)", minVersion: "3.0", info: "Returns the value for a key in a map, or the empty sequence", blogSlug: "xpath-map-get" },
+ { label: "map:put(map, key, value)", minVersion: "3.0", info: "Returns a new map with the key-value pair added or updated", blogSlug: "xpath-map-put" },
+ { label: "map:remove(map, keys)", minVersion: "3.0", info: "Returns a new map with specified keys removed", blogSlug: "xpath-map-remove" },
+ { label: "map:entry(key, value)", minVersion: "3.0", info: "Creates a singleton map with one key-value entry", blogSlug: "xpath-map-entry" },
// 3.0 array
- { label: "array:size(array)", minVersion: "3.0", info: "Returns the number of members in an array" },
- { label: "array:get(array, pos)", minVersion: "3.0", info: "Returns the member at a 1-based position" },
- { label: "array:put(array, pos, val)", minVersion: "3.0", info: "Returns a new array with a member replaced" },
- { label: "array:append(array, val)", minVersion: "3.0", info: "Appends a member to an array" },
- { label: "array:head(array)", minVersion: "3.0", info: "Returns the first member of an array" },
- { label: "array:tail(array)", minVersion: "3.0", info: "Returns all but the first member of an array" },
- { label: "array:reverse(array)", minVersion: "3.0", info: "Reverses an array" },
- { label: "array:join(arrays)", minVersion: "3.0", info: "Concatenates multiple arrays" },
- { label: "array:subarray(array, start, length?)", minVersion: "3.0", info: "Returns a sub-array" },
- { label: "array:remove(array, positions)", minVersion: "3.0", info: "Removes members at specified positions" },
- { label: "array:insert-before(array, pos, members)", minVersion: "3.0", info: "Inserts members before a position" },
- { label: "array:for-each(array, func)", minVersion: "3.0", info: "Applies a function to each member of an array" },
- { label: "array:filter(array, func)", minVersion: "3.0", info: "Filters array members by a predicate" },
- { label: "array:fold-left(array, zero, func)", minVersion: "3.0", info: "Left-fold over an array" },
- { label: "array:fold-right(array, zero, func)", minVersion: "3.0", info: "Right-fold over an array" },
- { label: "array:for-each-pair(arr1, arr2, func)", minVersion: "3.0", info: "Applies a function to pairs from two arrays" },
- { label: "array:sort(array, collation?, key?)", minVersion: "3.0", info: "Sorts an array" },
- { label: "array:flatten(items)", minVersion: "3.0", info: "Recursively flattens arrays to a sequence" },
+ { label: "array:size(array)", minVersion: "3.0", info: "Returns the number of members in an array", blogSlug: "xpath-array-size" },
+ { label: "array:get(array, pos)", minVersion: "3.0", info: "Returns the member at a 1-based position", blogSlug: "xpath-array-get" },
+ { label: "array:put(array, pos, val)", minVersion: "3.0", info: "Returns a new array with a member replaced", blogSlug: "xpath-array-put" },
+ { label: "array:append(array, val)", minVersion: "3.0", info: "Appends a member to an array", blogSlug: "xpath-array-append" },
+ { label: "array:head(array)", minVersion: "3.0", info: "Returns the first member of an array", blogSlug: "xpath-array-head" },
+ { label: "array:tail(array)", minVersion: "3.0", info: "Returns all but the first member of an array", blogSlug: "xpath-array-tail" },
+ { label: "array:reverse(array)", minVersion: "3.0", info: "Reverses an array", blogSlug: "xpath-array-reverse" },
+ { label: "array:join(arrays)", minVersion: "3.0", info: "Concatenates multiple arrays", blogSlug: "xpath-array-join" },
+ { label: "array:subarray(array, start, length?)", minVersion: "3.0", info: "Returns a sub-array", blogSlug: "xpath-array-subarray" },
+ { label: "array:remove(array, positions)", minVersion: "3.0", info: "Removes members at specified positions", blogSlug: "xpath-array-remove" },
+ { label: "array:insert-before(array, pos, members)", minVersion: "3.0", info: "Inserts members before a position", blogSlug: "xpath-array-insert-before" },
+ { label: "array:for-each(array, func)", minVersion: "3.0", info: "Applies a function to each member of an array", blogSlug: "xpath-array-for-each" },
+ { label: "array:filter(array, func)", minVersion: "3.0", info: "Filters array members by a predicate", blogSlug: "xpath-array-filter" },
+ { label: "array:fold-left(array, zero, func)", minVersion: "3.0", info: "Left-fold over an array", blogSlug: "xpath-array-fold-left" },
+ { label: "array:fold-right(array, zero, func)", minVersion: "3.0", info: "Right-fold over an array", blogSlug: "xpath-array-fold-right" },
+ { label: "array:for-each-pair(arr1, arr2, func)", minVersion: "3.0", info: "Applies a function to pairs from two arrays", blogSlug: "xpath-array-for-each-pair" },
+ { label: "array:sort(array, collation?, key?)", minVersion: "3.0", info: "Sorts an array", blogSlug: "xpath-array-sort" },
+ { label: "array:flatten(items)", minVersion: "3.0", info: "Recursively flattens arrays to a sequence", blogSlug: "xpath-array-flatten" },
// 3.0 misc
- { label: "environment-variable(name)", minVersion: "3.0", info: "Returns the value of an environment variable (if available)" },
- { label: "available-environment-variables()", minVersion: "3.0", info: "Returns the names of available environment variables" },
- { label: "unparsed-text(uri, encoding?)", minVersion: "2.0", info: "Reads a text file and returns it as a string" },
- { label: "unparsed-text-lines(uri, encoding?)", minVersion: "2.0", info: "Reads a text file and returns lines as a sequence" },
- { label: "unparsed-text-available(uri, encoding?)", minVersion: "2.0", info: "Returns true if unparsed-text() would succeed" },
- { label: "uri-collection(uri?)", minVersion: "2.0", info: "Returns a sequence of URIs from a collection" },
- { label: "collection(uri?)", minVersion: "2.0", info: "Returns a sequence of nodes from a collection" },
- { label: "json-doc(uri, options?)", minVersion: "3.0", info: "Parses a JSON document from a URI into an XDM map/array" },
- { label: "json-to-xml(str, options?)", minVersion: "3.0", info: "Converts a JSON string to an XML representation" },
- { label: "xml-to-json(node, options?)", minVersion: "3.0", info: "Converts an XML node to a JSON string" },
- { label: "parse-json(str, options?)", minVersion: "3.0", info: "Parses a JSON string into an XDM map/array/atomic value" },
- { label: "serialize(node, params?)", minVersion: "3.0", info: "Serializes a node or sequence to a string" },
- { label: "parse-xml(str)", minVersion: "2.0", info: "Parses a string as XML and returns a document node" },
- { label: "parse-xml-fragment(str)", minVersion: "2.0", info: "Parses a well-balanced XML fragment" },
- { label: "has-children(node?)", minVersion: "3.0", info: "Returns true if the node has child nodes" },
- { label: "innermost(nodes)", minVersion: "3.0", info: "Returns the nodes that are not ancestors of any other node in the set" },
- { label: "outermost(nodes)", minVersion: "3.0", info: "Returns the nodes that are not descendants of any other node in the set" },
- { label: "path(node?)", minVersion: "3.0", info: "Returns an XPath expression describing the path to the node" },
- { label: "generate-id(node?)", minVersion: "1.0", info: "Returns a unique string identifier for a node" },
- { label: "accumulator-before(name)", minVersion: "3.0", info: "Returns the value of an accumulator before processing the current node" },
- { label: "accumulator-after(name)", minVersion: "3.0", info: "Returns the value of an accumulator after processing the current node" },
- { label: "current-group()", minVersion: "2.0", info: "Returns the current group within xsl:for-each-group" },
- { label: "current-grouping-key()", minVersion: "2.0", info: "Returns the grouping key of the current group" },
- { label: "current-merge-group(source?)", minVersion: "3.0", info: "Returns the current merge group within xsl:merge" },
- { label: "current-merge-key()", minVersion: "3.0", info: "Returns the current merge key within xsl:merge" },
- { label: "current-output-uri()", minVersion: "2.0", info: "Returns the URI of the current output document" },
- { label: "regex-group(n)", minVersion: "2.0", info: "Returns a captured group from xsl:analyze-string" },
- { label: "type-available(type)", minVersion: "2.0", info: "Returns true if a schema type is available" },
- { label: "copy-of(seq)", minVersion: "2.0", info: "Returns a deep copy of a sequence (XQuery/XPath 2.0)" },
- { label: "snapshot(seq)", minVersion: "3.0", info: "Returns a snapshot of the sequence (for streaming)" },
+ { label: "environment-variable(name)", minVersion: "3.0", info: "Returns the value of an environment variable (if available)", blogSlug: "xpath-environment-variable" },
+ { label: "available-environment-variables()", minVersion: "3.0", info: "Returns the names of available environment variables", blogSlug: "xpath-available-environment-variables" },
+ { label: "unparsed-text(uri, encoding?)", minVersion: "2.0", info: "Reads a text file and returns it as a string", blogSlug: "xpath-unparsed-text" },
+ { label: "unparsed-text-lines(uri, encoding?)", minVersion: "2.0", info: "Reads a text file and returns lines as a sequence", blogSlug: "xpath-unparsed-text-lines" },
+ { label: "unparsed-text-available(uri, encoding?)", minVersion: "2.0", info: "Returns true if unparsed-text() would succeed", blogSlug: "xpath-unparsed-text-available" },
+ { label: "uri-collection(uri?)", minVersion: "2.0", info: "Returns a sequence of URIs from a collection", blogSlug: "xpath-uri-collection" },
+ { label: "collection(uri?)", minVersion: "2.0", info: "Returns a sequence of nodes from a collection", blogSlug: "xpath-collection" },
+ { label: "json-doc(uri, options?)", minVersion: "3.0", info: "Parses a JSON document from a URI into an XDM map/array", blogSlug: "xpath-json-doc" },
+ { label: "json-to-xml(str, options?)", minVersion: "3.0", info: "Converts a JSON string to an XML representation", blogSlug: "xpath-json-to-xml" },
+ { label: "xml-to-json(node, options?)", minVersion: "3.0", info: "Converts an XML node to a JSON string", blogSlug: "xpath-xml-to-json" },
+ { label: "parse-json(str, options?)", minVersion: "3.0", info: "Parses a JSON string into an XDM map/array/atomic value", blogSlug: "xpath-parse-json" },
+ { label: "serialize(node, params?)", minVersion: "3.0", info: "Serializes a node or sequence to a string", blogSlug: "xpath-serialize" },
+ { label: "parse-xml(str)", minVersion: "2.0", info: "Parses a string as XML and returns a document node", blogSlug: "xpath-parse-xml" },
+ { label: "parse-xml-fragment(str)", minVersion: "2.0", info: "Parses a well-balanced XML fragment", blogSlug: "xpath-parse-xml-fragment" },
+ { label: "has-children(node?)", minVersion: "3.0", info: "Returns true if the node has child nodes", blogSlug: "xpath-has-children" },
+ { label: "innermost(nodes)", minVersion: "3.0", info: "Returns the nodes that are not ancestors of any other node in the set", blogSlug: "xpath-innermost" },
+ { label: "outermost(nodes)", minVersion: "3.0", info: "Returns the nodes that are not descendants of any other node in the set", blogSlug: "xpath-outermost" },
+ { label: "path(node?)", minVersion: "3.0", info: "Returns an XPath expression describing the path to the node", blogSlug: "xpath-path" },
+ { label: "generate-id(node?)", minVersion: "1.0", info: "Returns a unique string identifier for a node", blogSlug: "xpath-generate-id" },
+ { label: "accumulator-before(name)", minVersion: "3.0", info: "Returns the value of an accumulator before processing the current node", blogSlug: "xpath-accumulator-before" },
+ { label: "accumulator-after(name)", minVersion: "3.0", info: "Returns the value of an accumulator after processing the current node", blogSlug: "xpath-accumulator-after" },
+ { label: "current-group()", minVersion: "2.0", info: "Returns the current group within xsl:for-each-group", blogSlug: "xpath-current-group" },
+ { label: "current-grouping-key()", minVersion: "2.0", info: "Returns the grouping key of the current group", blogSlug: "xpath-current-grouping-key" },
+ { label: "current-merge-group(source?)", minVersion: "3.0", info: "Returns the current merge group within xsl:merge", blogSlug: "xpath-current-merge-group" },
+ { label: "current-merge-key()", minVersion: "3.0", info: "Returns the current merge key within xsl:merge", blogSlug: "xpath-current-merge-key" },
+ { label: "current-output-uri()", minVersion: "2.0", info: "Returns the URI of the current output document", blogSlug: "xpath-current-output-uri" },
+ { label: "regex-group(n)", minVersion: "2.0", info: "Returns a captured group from xsl:analyze-string", blogSlug: "xpath-regex-group" },
+ { label: "type-available(type)", minVersion: "2.0", info: "Returns true if a schema type is available", blogSlug: "xpath-type-available" },
+ { label: "copy-of(seq)", minVersion: "2.0", info: "Returns a deep copy of a sequence (XQuery/XPath 2.0)", blogSlug: "xpath-copy-of" },
+ { label: "snapshot(seq)", minVersion: "3.0", info: "Returns a snapshot of the sequence (for streaming)", blogSlug: "xpath-snapshot" },
];
const VERSION_ORDER = { "1.0": 1, "2.0": 2, "3.0": 3 };
diff --git a/site/content/xslt/functions/xpath-abs.md b/site/content/xslt/functions/xpath-abs.md
new file mode 100644
index 00000000..07d61196
--- /dev/null
+++ b/site/content/xslt/functions/xpath-abs.md
@@ -0,0 +1,107 @@
+---
+title: "abs()"
+description: "Returns the absolute value of a numeric argument, removing any negative sign while preserving the numeric type."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "numeric function"
+syntax: "abs(number)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`abs()` returns the absolute (non-negative) value of its argument. The result has the same type as the input: `xs:integer` in gives `xs:integer` out, `xs:double` in gives `xs:double` out. If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `number` | xs:numeric? | Yes | The numeric value whose absolute value is required. |
+
+## Return value
+
+`xs:numeric?` — same type and precision as the input, but non-negative. Returns the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Absolute value of a negative attribute
+
+**Input XML:**
+```xml
+
+
+ -42
+ 17
+ -3.14
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 42
+ 17
+ 3.14
+
+```
+
+### Computing deviation from a target value
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (for values -42, 17, -3.14 against target 10):**
+```xml
+
+ 52
+ 7
+ 13.14
+
+```
+
+## Notes
+
+- `abs()` is defined in XPath 2.0 and is not available in XSLT 1.0. In XSLT 1.0, absolute value required a workaround such as `translate(., '-', '')` or a conditional expression.
+- The function preserves numeric type: `abs(xs:float(-1.0))` returns `xs:float(1.0)`.
+- `abs(xs:double('NaN'))` returns `NaN`; `abs(xs:double('-INF'))` returns `INF`.
+
+## See also
+
+- [avg()](../xpath-avg)
+- [min()](../xpath-min)
+- [max()](../xpath-max)
diff --git a/site/content/xslt/functions/xpath-accumulator-after.md b/site/content/xslt/functions/xpath-accumulator-after.md
new file mode 100644
index 00000000..7959579d
--- /dev/null
+++ b/site/content/xslt/functions/xpath-accumulator-after.md
@@ -0,0 +1,116 @@
+---
+title: "accumulator-after()"
+description: "Returns the value of a named accumulator computed after processing the current node in streaming mode."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "accumulator-after(name)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`accumulator-after()` returns the value of a named accumulator as computed just after all accumulator rules for the current node have been applied. It is the counterpart to `accumulator-before()`: where `accumulator-before()` gives the value before the node's rule fires, `accumulator-after()` gives the updated value reflecting the current node's contribution.
+
+The function is only meaningful in contexts where an accumulator rule for the named accumulator has a match for the current node. If no rule matches, before and after values are identical.
+
+Both accumulator functions are essential for streaming transformations where you cannot revisit nodes. They allow you to carry state forward through the document without storing nodes in memory.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:string | Yes | The name of the accumulator to read. |
+
+## Return value
+
+The declared return type of the named accumulator — the value computed after the current node's accumulator rule has been applied.
+
+## Examples
+
+### Cumulative total after each node
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+### Final accumulator value on the parent
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+200
+```
+
+## Notes
+
+- `accumulator-after()` on a node with no matching accumulator rule returns the same value as `accumulator-before()`.
+- Accumulators must be listed in the `use-accumulators` attribute of the template or `xsl:use-accumulators` instruction to be active for that template.
+- Accumulators are phase-ordered: all accumulator rules are applied before any template generates output for a given node.
+- In XSLT 3.0 packages, accumulators can be imported and their visibility controlled with `xsl:expose`.
+
+## See also
+
+- [accumulator-before()](../xpath-accumulator-before)
+- [snapshot()](../xpath-snapshot)
+- [xsl:use-accumulators](../xsl-use-accumulators)
diff --git a/site/content/xslt/functions/xpath-accumulator-before.md b/site/content/xslt/functions/xpath-accumulator-before.md
new file mode 100644
index 00000000..88deac8f
--- /dev/null
+++ b/site/content/xslt/functions/xpath-accumulator-before.md
@@ -0,0 +1,119 @@
+---
+title: "accumulator-before()"
+description: "Returns the value of a named accumulator computed before processing the current node in streaming mode."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "accumulator-before(name)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`accumulator-before()` returns the value of a named accumulator as it was just before the current node was processed. Accumulators are XSLT 3.0 constructs that compute running values as the processor traverses a document — similar to a running total or state machine. The "before" value reflects the accumulator state prior to applying any accumulator rule for the current node.
+
+The function is used inside `xsl:accumulator-rule` actions and in template rules that access accumulator state. The `name` argument is a string literal matching the `name` attribute of an `xsl:accumulator` declaration.
+
+For the function to be available in a template, the template must declare the accumulator in its `use-accumulators` attribute (or via `xsl:use-accumulators`).
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:string | Yes | The name of the accumulator to read. |
+
+## Return value
+
+The declared return type of the named accumulator — the value computed just before the current node is entered.
+
+## Examples
+
+### Running total accumulator
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+### Comparing before and after values
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+```
+
+## Notes
+
+- `accumulator-before()` reads the accumulator value before the node's rule fires; `accumulator-after()` reads it after.
+- The accumulator must be declared with `xsl:accumulator` at the top level and listed in the template's `use-accumulators` attribute.
+- Accumulators are primarily designed for streaming, but they also work in non-streaming transformations.
+- The initial value is used as the "before" value for the first matched node.
+
+## See also
+
+- [accumulator-after()](../xpath-accumulator-after)
+- [snapshot()](../xpath-snapshot)
+- [xsl:use-accumulators](../xsl-use-accumulators)
diff --git a/site/content/xslt/functions/xpath-apply.md b/site/content/xslt/functions/xpath-apply.md
new file mode 100644
index 00000000..204036b0
--- /dev/null
+++ b/site/content/xslt/functions/xpath-apply.md
@@ -0,0 +1,118 @@
+---
+title: "apply()"
+description: "Calls a function item with arguments supplied as an array, enabling dynamic dispatch with a variable argument list."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "apply(function, array-of-args)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`apply()` invokes a function item, passing its arguments as members of an array. This enables dynamic function calls where both the function and its argument list are determined at runtime. The number of array members must match the arity of the function, otherwise a type error is raised.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `function` | function(*) | Yes | The function item to invoke. |
+| `array-of-args` | array(*) | Yes | An array whose members are the arguments to pass. Member count must equal the function arity. |
+
+## Return value
+
+`item()*` — the result returned by the invoked function.
+
+## Examples
+
+### Dynamic dispatch with apply()
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 10
+
+```
+
+### Applying a selected operation dynamically
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ HELLO
+ world
+
+```
+
+## Notes
+
+- `apply()` is defined in XPath 3.0 / XSLT 3.0. It is not available in XSLT 2.0 or earlier.
+- The function arity must exactly match the number of members in the array; a mismatch causes `err:FOAP0001`.
+- `apply()` is the complement of inline function items and partial function application.
+- Useful for implementing dispatch tables and strategy patterns in XSLT.
+
+## See also
+
+- [function-lookup()](../xpath-function-lookup)
+- [function-name()](../xpath-function-name)
+- [function-arity()](../xpath-function-arity)
+- [for-each()](../xpath-for-each)
diff --git a/site/content/xslt/functions/xpath-array-append.md b/site/content/xslt/functions/xpath-array-append.md
new file mode 100644
index 00000000..9313788f
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-append.md
@@ -0,0 +1,119 @@
+---
+title: "array:append()"
+description: "Returns a new array with an additional member appended at the end."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:append(array, appendage)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:append()` returns a new array that is a copy of the input array with the `appendage` value added as a new final member. The appendage is added as a single member regardless of whether it is a sequence, making it distinct from `array:join()` which concatenates arrays.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The source array. |
+| `appendage` | item()* | Yes | The value to add as the new last member. |
+
+## Return value
+
+`array(*)` — a new array with `array:size()` increased by 1.
+
+## Examples
+
+### Building an array by appending
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - alpha
+ - beta
+ - gamma
+ - delta
+
+```
+
+### Accumulating results into an array with fold-left
+
+**Input XML:**
+```xml
+
+
+ 85
+ 92
+ 78
+ 96
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 4
+ 96
+
+```
+
+## Notes
+
+- The `appendage` is added as a single member; if it is a sequence `(1,2)`, the new member is that two-item sequence, not two separate members.
+- To concatenate two arrays end-to-end, use `array:join(($arr1, $arr2))`.
+- Arrays are immutable; `array:append()` always returns a new array.
+
+## See also
+
+- [array:join()](../xpath-array-join)
+- [array:insert-before()](../xpath-array-insert-before)
+- [array:remove()](../xpath-array-remove)
+- [array:size()](../xpath-array-size)
+- [xsl:array](../xsl-array)
+- [xsl:array-member](../xsl-array-member)
diff --git a/site/content/xslt/functions/xpath-array-filter.md b/site/content/xslt/functions/xpath-array-filter.md
new file mode 100644
index 00000000..ab32733b
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-filter.md
@@ -0,0 +1,131 @@
+---
+title: "array:filter()"
+description: "Returns a new array containing only the members for which a predicate function returns true."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:filter(array, predicate)"
+tags: ["xslt", "reference", "xslt3", "xpath"]
+---
+
+## Description
+
+`array:filter()` applies a predicate function to each member of the input array and returns a new array containing only the members for which the predicate returns `true`. The order of surviving members is preserved and the original array is not modified.
+
+The predicate is an inline or named function with signature `function(item()*) as xs:boolean`. Each member of the array—whether it is a single item or a sequence—is passed to the predicate as a whole unit.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | `array(*)` | Yes | The source array whose members are tested. |
+| `predicate` | `function(item()*) as xs:boolean` | Yes | A function that returns true for members to keep. |
+
+## Return value
+
+`array(*)` — a new array containing only the members for which the predicate returned `true`. The size may be zero if no members pass.
+
+## Examples
+
+### Filtering numbers greater than 5
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 8
+ 4
+ 7
+ 9
+ 6
+ 8
+
+```
+
+### Filtering non-empty strings from an XML source
+
+**Input XML:**
+```xml
+
+
+ xslt
+
+ xpath
+
+ saxon
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ xslt
+ xpath
+ saxon
+
+```
+
+## Notes
+
+- Each array member is passed as a whole unit to the predicate. A member that is itself a sequence is passed as that sequence, not as individual items.
+- `array:filter()` always returns a new array; the source array is unmodified.
+- To apply a transformation rather than a selection, use `array:for-each()`.
+- If no member satisfies the predicate, an empty array `[]` is returned.
+
+## See also
+
+- [array:for-each()](../xpath-array-for-each)
+- [array:fold-left()](../xpath-array-fold-left)
+- [array:remove()](../xpath-array-remove)
+- [array:size()](../xpath-array-size)
diff --git a/site/content/xslt/functions/xpath-array-flatten.md b/site/content/xslt/functions/xpath-array-flatten.md
new file mode 100644
index 00000000..52bbe848
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-flatten.md
@@ -0,0 +1,128 @@
+---
+title: "array:flatten()"
+description: "Recursively flattens nested arrays into a single flat sequence of atomic items and nodes."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:flatten(items)"
+tags: ["xslt", "reference", "xslt3", "xpath"]
+---
+
+## Description
+
+`array:flatten()` takes a sequence of items that may contain arrays—including arrays nested inside arrays—and returns a flat sequence in which every array has been dissolved. Non-array items (strings, integers, nodes, maps, etc.) pass through unchanged; only array wrappers are removed.
+
+The recursion is unbounded: a three-level-deep nesting such as `[[1, [2, 3]], [4]]` is fully flattened to `(1, 2, 3, 4)`. This makes `array:flatten()` useful when assembling arrays incrementally or when consuming data structures of unknown depth.
+
+Note that the result is a **sequence**, not an array. Wrap it in `array:join()` if an array is required.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `items` | `item()*` | Yes | A sequence of items, which may include arrays at any depth of nesting. |
+
+## Return value
+
+`item()*` — a flat sequence with all array wrappers removed. Maps are not unwrapped; only arrays are affected.
+
+## Examples
+
+### Flattening nested integer arrays
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 1, 2, 3, 4, 5, 6
+ 21
+
+```
+
+### Normalising a heterogeneous collection before processing
+
+**Input XML:**
+```xml
+
+
+
+ - alpha
+ - beta
+
+
+ - gamma
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - alpha
+ - beta
+ - gamma
+
+```
+
+## Notes
+
+- Only arrays are unwrapped. Maps, even though they are also XDM structured types, are left intact.
+- The function accepts a plain sequence as its argument, not only an array. Items in the sequence that are not arrays pass through unchanged.
+- Members that are sequences (e.g. a member holding `(1, 2)`) remain as sequences inside the result because they are not themselves arrays.
+- To convert the resulting sequence back into an array, use `array:join()` with individual wrapping: `array:join(for $x in array:flatten($arr) return [$x])`.
+
+## See also
+
+- [array:join()](../xpath-array-join)
+- [array:for-each()](../xpath-array-for-each)
+- [array:fold-left()](../xpath-array-fold-left)
diff --git a/site/content/xslt/functions/xpath-array-fold-left.md b/site/content/xslt/functions/xpath-array-fold-left.md
new file mode 100644
index 00000000..ec211c81
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-fold-left.md
@@ -0,0 +1,127 @@
+---
+title: "array:fold-left()"
+description: "Accumulates a result by applying a function to each array member from left to right, starting with a seed value."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:fold-left(array, zero, function)"
+tags: ["xslt", "reference", "xslt3", "xpath"]
+---
+
+## Description
+
+`array:fold-left()` processes an array from its first member to its last, threading an accumulator through each step. For each member, the supplied function is called with the current accumulator value and the current member; its return value becomes the accumulator for the next step. After all members have been processed, the final accumulator value is returned.
+
+When the array is empty, the `zero` (seed) value is returned unchanged without calling the function. This mirrors the mathematical notion of a left fold and is equivalent to the XPath 3.0 `fold-left()` function applied to sequences.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | `array(*)` | Yes | The array to fold. |
+| `zero` | `item()*` | Yes | The initial accumulator value, returned as-is when the array is empty. |
+| `function` | `function(item()*, item()*) as item()*` | Yes | A function taking `(accumulator, member)` and returning the new accumulator. |
+
+## Return value
+
+`item()*` — the final accumulated result after processing all members.
+
+## Examples
+
+### Summing an array of numbers
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 30
+ 10
+
+```
+
+### Building a CSV line from an array of strings
+
+**Input XML:**
+```xml
+
+
+ Alice
+ Engineering
+ London
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+Alice,Engineering,London
+```
+
+## Notes
+
+- `array:fold-left()` and `array:fold-right()` differ in the direction of traversal, which matters for non-commutative operations such as string concatenation or subtraction.
+- The zero value type must be compatible with the accumulator type expected by the function; Saxon enforces type consistency at runtime.
+- For very large arrays, folding is generally more efficient than recursive template calls because it avoids XSL overhead.
+- The XPath 3.0 `fold-left()` function (without the `array:` prefix) performs the same operation over sequences rather than arrays.
+
+## See also
+
+- [array:fold-right()](../xpath-array-fold-right)
+- [array:for-each()](../xpath-array-for-each)
+- [array:filter()](../xpath-array-filter)
+- [array:size()](../xpath-array-size)
diff --git a/site/content/xslt/functions/xpath-array-fold-right.md b/site/content/xslt/functions/xpath-array-fold-right.md
new file mode 100644
index 00000000..3527a51f
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-fold-right.md
@@ -0,0 +1,127 @@
+---
+title: "array:fold-right()"
+description: "Accumulates a result by applying a function to each array member from right to left, starting with a seed value."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:fold-right(array, zero, function)"
+tags: ["xslt", "reference", "xslt3", "xpath"]
+---
+
+## Description
+
+`array:fold-right()` traverses an array from its last member to its first, threading an accumulator through each step. For each member the supplied function is called with the current member and the current accumulator; its return value becomes the accumulator for the next (earlier) member. The final accumulator value after processing the first member is returned.
+
+When the array is empty the `zero` seed is returned unchanged. The key distinction from `array:fold-left()` is the traversal direction and the argument order to the function: the member comes first, then the accumulator. This matters for operations that are not commutative, such as building a prefix string or constructing a right-associated structure.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | `array(*)` | Yes | The array to fold. |
+| `zero` | `item()*` | Yes | The initial accumulator value, returned as-is when the array is empty. |
+| `function` | `function(item()*, item()*) as item()*` | Yes | A function taking `(member, accumulator)` and returning the new accumulator. |
+
+## Return value
+
+`item()*` — the final accumulated result after processing all members from right to left.
+
+## Examples
+
+### Concatenating strings in reverse accumulation order
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ one > two > three > four
+ one > two > three > four
+
+```
+
+### Building a nested XML structure from right to left
+
+**Input XML:**
+```xml
+
+
+ root
+ section
+ paragraph
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+root / section / paragraph / END
+```
+
+## Notes
+
+- The function signature for `array:fold-right()` is `function(member, accumulator)`, while `array:fold-left()` uses `function(accumulator, member)`. Confusing the argument order is a common mistake.
+- For commutative operations (addition, min, max) the fold direction produces the same result; for string concatenation and list building the direction matters.
+- Like all array functions, the operation returns a new value; no existing array is modified.
+- The XPath 3.0 sequence function `fold-right()` (without `array:` prefix) is the equivalent for ordinary sequences.
+
+## See also
+
+- [array:fold-left()](../xpath-array-fold-left)
+- [array:for-each()](../xpath-array-for-each)
+- [array:filter()](../xpath-array-filter)
diff --git a/site/content/xslt/functions/xpath-array-for-each-pair.md b/site/content/xslt/functions/xpath-array-for-each-pair.md
new file mode 100644
index 00000000..79dcdb2d
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-for-each-pair.md
@@ -0,0 +1,115 @@
+---
+title: "array:for-each-pair()"
+description: "Returns a new array by applying the function to corresponding members of two arrays of the same size."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:for-each-pair(array1, array2, function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:for-each-pair()` applies a two-argument function to corresponding members of two arrays and returns a new array of the results. The function is called with the member from the first array and the member from the second array at each position. The two input arrays must have the same size; if they differ, a dynamic error is raised.
+
+This function is the array analogue of the `for-each-pair()` higher-order function for sequences. It enables pairwise operations — such as computing differences, combining data from parallel arrays, or zipping two arrays together.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array1` | array(*) | Yes | The first input array. |
+| `array2` | array(*) | Yes | The second input array, must be the same size as array1. |
+| `function` | function(item()*, item()*) as item()* | Yes | A two-argument function applied to corresponding members. |
+
+## Return value
+
+`array(*)` — a new array of the same size, where each member is the result of applying the function to the corresponding pair of members.
+
+## Examples
+
+### Adding corresponding elements
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 11
+ 22
+ 33
+
+```
+
+### Zipping names with scores
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice:95
+ Bob:82
+ Carol:91
+
+```
+
+## Notes
+
+- Both arrays must have the same number of members. If the sizes differ, a dynamic error is raised.
+- Each member is passed to the function as a sequence — a single-item member is a sequence of length one.
+- The result array has the same size as the inputs.
+- To process a single array with a two-argument function that also tracks the index, combine `array:for-each-pair()` with a position array created via `array:join(for $i in 1 to array:size($a) return [$i])`.
+
+## See also
+
+- [array:for-each()](../xpath-array-for-each)
+- [array:filter()](../xpath-array-filter)
+- [array:fold-left()](../xpath-array-fold-left)
+- [array:flatten()](../xpath-array-flatten)
diff --git a/site/content/xslt/functions/xpath-array-for-each.md b/site/content/xslt/functions/xpath-array-for-each.md
new file mode 100644
index 00000000..ba951e4a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-for-each.md
@@ -0,0 +1,115 @@
+---
+title: "array:for-each()"
+description: "Returns a new array where each member is the result of applying the function to the corresponding member of the input array."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:for-each(array, function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:for-each()` applies a function to each member of an array and returns a new array of the same size, where each member is the result of the function applied to the corresponding input member. The original array is not modified.
+
+The function argument takes a single parameter: the current array member, which is a sequence. The function may return any XDM value — a single item, a sequence, or even an empty sequence — and the result becomes the corresponding member of the output array.
+
+`array:for-each()` is the array equivalent of the sequence-level `for-each()` higher-order function, but it preserves array structure rather than flattening to a sequence.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The input array. |
+| `function` | function(item()*) as item()* | Yes | A function applied to each member. |
+
+## Return value
+
+`array(*)` — a new array of the same size as the input, with each member replaced by the function result.
+
+## Examples
+
+### Squaring each element
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 1
+ 4
+ 9
+ 16
+ 25
+
+```
+
+### Uppercasing string members
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ ALPHA
+ BETA
+ GAMMA
+
+```
+
+## Notes
+
+- `array:for-each()` always produces a new array of the same size as the input; it cannot drop or add members. Use `array:filter()` to remove members.
+- Named functions can be referenced using the function-reference syntax (`name#arity`) as shown in the second example.
+- Unlike `array:fold-left()`, `array:for-each()` does not accumulate state across members; each call is independent.
+- An empty array produces an empty array.
+
+## See also
+
+- [array:filter()](../xpath-array-filter)
+- [array:fold-left()](../xpath-array-fold-left)
+- [array:for-each-pair()](../xpath-array-for-each-pair)
+- [array:flatten()](../xpath-array-flatten)
diff --git a/site/content/xslt/functions/xpath-array-get.md b/site/content/xslt/functions/xpath-array-get.md
new file mode 100644
index 00000000..a89fc8a7
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-get.md
@@ -0,0 +1,110 @@
+---
+title: "array:get()"
+description: "Returns the member of an array at a specified 1-based position."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:get(array, position)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:get()` retrieves the member at the given 1-based integer position in an array. If the position is less than 1 or greater than the array size, error `err:FOAY0001` is raised. An alternative shorthand is `$array($position)` using function-call syntax.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The array to access. |
+| `position` | xs:integer | Yes | The 1-based position of the member to retrieve. |
+
+## Return value
+
+`item()*` — the member at the given position (may be a sequence if the member is a sequence).
+
+## Examples
+
+### Accessing array elements by position
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ red
+ blue
+ yellow
+
+```
+
+### Iterating with positional access
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ | 1 | 2 | 3 |
+ | 4 | 5 | 6 |
+ | 7 | 8 | 9 |
+
+```
+
+## Notes
+
+- Positions are 1-based (not 0-based), consistent with XPath sequence indexing.
+- Out-of-bounds access raises `err:FOAY0001`; use `array:size()` to guard.
+- The shorthand `$array($pos)` is syntactic sugar for `array:get($array, $pos)`.
+
+## See also
+
+- [array:size()](../xpath-array-size)
+- [array:head()](../xpath-array-head)
+- [array:put()](../xpath-array-put)
+- [array:subarray()](../xpath-array-subarray)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-array-head.md b/site/content/xslt/functions/xpath-array-head.md
new file mode 100644
index 00000000..a4402749
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-head.md
@@ -0,0 +1,104 @@
+---
+title: "array:head()"
+description: "Returns the first member of an array; raises an error if the array is empty."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:head(array)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:head()` returns the value of the first member of an array. If the array is empty, error `err:FOAY0001` is raised. Together with `array:tail()`, it supports recursive pattern-matching style processing over arrays.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The array whose first member is to be returned. |
+
+## Return value
+
+`item()*` — the first member (which may itself be a sequence).
+
+## Examples
+
+### Accessing the first element safely
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ first
+
+```
+
+### Recursive processing with head and tail
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 100
+
+```
+
+## Notes
+
+- Equivalent to `array:get($array, 1)`.
+- Raises `err:FOAY0001` on an empty array; guard with `array:size($arr) gt 0`.
+- Pair with `array:tail()` for list-processing patterns.
+
+## See also
+
+- [array:tail()](../xpath-array-tail)
+- [array:get()](../xpath-array-get)
+- [array:size()](../xpath-array-size)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-array-insert-before.md b/site/content/xslt/functions/xpath-array-insert-before.md
new file mode 100644
index 00000000..f50e3d63
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-insert-before.md
@@ -0,0 +1,108 @@
+---
+title: "array:insert-before()"
+description: "Returns a new array with the given members inserted before the specified 1-based position."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:insert-before(array, position, members)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:insert-before()` returns a new array formed by inserting one or more new members into the input array just before the specified position. The `position` argument is 1-based. Inserting before position 1 prepends to the array; inserting before `array:size($array) + 1` appends to the array.
+
+The `members` argument is treated as a sequence of new array members to insert, each becoming a separate member of the result array. This means the result array's size is `array:size(array) + count(members-sequence)`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The source array. |
+| `position` | xs:integer | Yes | The 1-based position before which to insert. |
+| `members` | item()* | Yes | The sequence of new members to insert. Each item in the sequence becomes a separate array member. |
+
+## Return value
+
+`array(*)` — a new array with the inserted members, larger than the original.
+
+## Examples
+
+### Inserting at the beginning
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+A B C D
+```
+
+### Inserting in the middle
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+
+```
+
+## Notes
+
+- Inserting before position `array:size($array) + 1` is equivalent to appending; use `array:append()` for clarity.
+- The `members` argument is a sequence; each item in the sequence becomes a separate array member. To insert a single member that is itself a sequence, wrap it in an array and use `array:join()`.
+- Positions outside the range 1 to `size + 1` raise a dynamic error.
+- The source array is not modified; `array:insert-before()` always returns a new array.
+
+## See also
+
+- [array:remove()](../xpath-array-remove)
+- [array:append()](../xpath-array-append)
+- [array:flatten()](../xpath-array-flatten)
+- [array:size()](../xpath-array-size)
diff --git a/site/content/xslt/functions/xpath-array-join.md b/site/content/xslt/functions/xpath-array-join.md
new file mode 100644
index 00000000..aee594da
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-join.md
@@ -0,0 +1,121 @@
+---
+title: "array:join()"
+description: "Concatenates a sequence of arrays into a single array by combining all their members."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:join(arrays)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:join()` takes a sequence of arrays and returns a single array whose members are all the members of the input arrays concatenated in order. An empty sequence of arrays returns an empty array. This is distinct from `array:append()` which adds a single new member.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `arrays` | array(*)* | Yes | A sequence of arrays to concatenate. |
+
+## Return value
+
+`array(*)` — a new array containing all members of all input arrays in order.
+
+## Examples
+
+### Joining two arrays
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - a
+ - b
+ - c
+ - d
+ - e
+ - f
+
+```
+
+### Building an array from chunked XML data
+
+**Input XML:**
+```xml
+
+
+ 1 2
+ 3 4
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 1 2 3 4
+
+```
+
+## Notes
+
+- `array:join(())` returns an empty array `[]`.
+- Unlike `array:append()`, which adds one item as a single member, `array:join()` merges the members of each array.
+- The result length equals the sum of the sizes of all input arrays.
+
+## See also
+
+- [array:append()](../xpath-array-append)
+- [array:subarray()](../xpath-array-subarray)
+- [array:size()](../xpath-array-size)
+- [array:flatten()](../xpath-array-flatten)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-array-put.md b/site/content/xslt/functions/xpath-array-put.md
new file mode 100644
index 00000000..187828ba
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-put.md
@@ -0,0 +1,115 @@
+---
+title: "array:put()"
+description: "Returns a new array with the member at a given position replaced by a new value."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:put(array, position, value)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:put()` produces a new array identical to the input except that the member at the specified 1-based position is replaced with the new value. Arrays are immutable in XDM; the original array is not modified. Out-of-range positions raise `err:FOAY0001`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The source array. |
+| `position` | xs:integer | Yes | The 1-based position of the member to replace. |
+| `value` | item()* | Yes | The new value for that position. |
+
+## Return value
+
+`array(*)` — a new array with the member at `position` replaced by `value`.
+
+## Examples
+
+### Replacing a member in an array
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - a
+ - B
+ - c
+ - d
+
+```
+
+### Updating JSON-like array data
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - original-1
+ - updated-value
+ - original-3
+
+```
+
+## Notes
+
+- Array positions are 1-based. Position `0` or greater than `array:size()` raises `err:FOAY0001`.
+- The new value can be any XDM value, including a sequence (which becomes a single multi-item member).
+- Arrays are immutable; the result is always a new array.
+
+## See also
+
+- [array:get()](../xpath-array-get)
+- [array:append()](../xpath-array-append)
+- [array:remove()](../xpath-array-remove)
+- [array:insert-before()](../xpath-array-insert-before)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-array-remove.md b/site/content/xslt/functions/xpath-array-remove.md
new file mode 100644
index 00000000..3fc91213
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-remove.md
@@ -0,0 +1,104 @@
+---
+title: "array:remove()"
+description: "Returns a new array with the members at the specified 1-based positions removed."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:remove(array, positions)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:remove()` returns a new array with specified members omitted. The `positions` argument is a sequence of 1-based integers identifying the members to remove. Positions may be supplied in any order; duplicates are ignored. Members not listed in `positions` are retained in their original relative order.
+
+If `positions` is the empty sequence, the function returns a copy of the input array unchanged. All specified positions must be valid (between 1 and `array:size(array)` inclusive); an out-of-range position raises a dynamic error.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The source array. |
+| `positions` | xs:integer* | Yes | A sequence of 1-based positions to remove. |
+
+## Return value
+
+`array(*)` — a new array with the specified members removed, preserving the relative order of remaining members.
+
+## Examples
+
+### Removing a single member
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+A C D
+```
+
+### Removing multiple members
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - 20
+ - 40
+ - 50
+
+```
+
+## Notes
+
+- `array:remove()` removes by position, not by value. To remove by value, combine `array:filter()` with a value comparison.
+- Positions are 1-based, consistent with all other array functions.
+- Duplicate positions in the `positions` sequence are silently ignored.
+- Removing all positions results in an empty array `[]`; removing no positions (`()`) returns a copy of the input.
+
+## See also
+
+- [array:insert-before()](../xpath-array-insert-before)
+- [array:filter()](../xpath-array-filter)
+- [array:subarray()](../xpath-array-subarray)
+- [array:size()](../xpath-array-size)
diff --git a/site/content/xslt/functions/xpath-array-reverse.md b/site/content/xslt/functions/xpath-array-reverse.md
new file mode 100644
index 00000000..b893af14
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-reverse.md
@@ -0,0 +1,121 @@
+---
+title: "array:reverse()"
+description: "Returns a new array with the members in reverse order."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:reverse(array)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:reverse()` returns a new array whose members are in the reverse order of the input array. The function is a convenience over manual head/tail recursion and operates on the array structure directly, preserving each member as-is (including members that are sequences).
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The array whose members are to be reversed. |
+
+## Return value
+
+`array(*)` — a new array with members in reverse order; an empty array if the input is empty.
+
+## Examples
+
+### Reversing a simple array
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 50
+ 40
+ 30
+ 20
+ 10
+
+```
+
+### Reversing a sorted array for descending order
+
+**Input XML:**
+```xml
+
+
+ 88 42 95 67
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 95
+ 88
+ 67
+ 42
+
+```
+
+## Notes
+
+- `array:reverse()` reverses member order only; individual members (including multi-item sequence members) are not affected internally.
+- An empty array returns an empty array without error.
+- For sequence reversal (not arrays), use `reverse()`.
+
+## See also
+
+- [array:sort()](../xpath-array-sort)
+- [array:subarray()](../xpath-array-subarray)
+- [array:head()](../xpath-array-head)
+- [array:tail()](../xpath-array-tail)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-array-size.md b/site/content/xslt/functions/xpath-array-size.md
new file mode 100644
index 00000000..3724bfdb
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-size.md
@@ -0,0 +1,107 @@
+---
+title: "array:size()"
+description: "Returns the number of members in an array."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:size(array)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:size()` returns the count of members in an array as an `xs:integer`. An empty array returns `0`. Unlike `count()` which operates on sequences, `array:size()` counts top-level members — each member may itself be a sequence or nested array.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The array whose member count is to be returned. |
+
+## Return value
+
+`xs:integer` — the number of top-level members; `0` for an empty array.
+
+## Examples
+
+### Checking array size before access
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ 0
+ red
+
+```
+
+### Comparing sequence count vs array size
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ 6
+
+```
+
+## Notes
+
+- `array:size()` counts top-level members; use `count(array:flatten($arr))` to count all atomic items recursively.
+- An array member that is an empty sequence still counts as one member.
+- Equivalent to `count(1 to array:size($arr))` but far more efficient.
+
+## See also
+
+- [array:get()](../xpath-array-get)
+- [array:head()](../xpath-array-head)
+- [array:tail()](../xpath-array-tail)
+- [array:flatten()](../xpath-array-flatten)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-array-sort.md b/site/content/xslt/functions/xpath-array-sort.md
new file mode 100644
index 00000000..23432114
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-sort.md
@@ -0,0 +1,112 @@
+---
+title: "array:sort()"
+description: "Returns a new array with members sorted using an optional collation and key function."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:sort(array, collation?, key-function?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:sort()` returns a new array whose members are in ascending order, determined by the sort key and collation. When no key function is supplied, members are compared directly using the default collation for strings or natural ordering for numbers and other atomic types. When a key function is supplied, it is applied to each member to derive the sort key; members are then sorted by their keys.
+
+This function is the array equivalent of `sort()` for sequences or `xsl:sort` in templates. It does not modify the input array; it always returns a new one.
+
+The `collation` argument controls string comparison. The `key-function` takes a single argument (the array member, which is a sequence) and returns an atomic value to use as the sort key.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The input array to sort. |
+| `collation` | xs:string? | No | URI of the collation to use for string comparison. Empty sequence uses the default. |
+| `key-function` | function(item()*) as xs:anyAtomicType* | No | A function that extracts the sort key from each member. |
+
+## Return value
+
+`array(*)` — a new array with the same members in sorted order.
+
+## Examples
+
+### Sorting numbers in ascending order
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+1 2 3 5 8 9
+```
+
+### Sorting records by a key field
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+## Notes
+
+- `array:sort()` always sorts in ascending order. To sort in descending order, reverse the result with `array:reverse()`.
+- The collation argument may be `()` (empty sequence) to use the default collation, allowing the key function to be specified without supplying a collation.
+- Members that are sequences are compared by their atomized value; members that cannot be compared raise a type error.
+- An empty array returns an empty array.
+
+## See also
+
+- [array:filter()](../xpath-array-filter)
+- [array:for-each()](../xpath-array-for-each)
+- [array:reverse()](../xpath-array-reverse)
+- [sort()](../xpath-sort)
diff --git a/site/content/xslt/functions/xpath-array-subarray.md b/site/content/xslt/functions/xpath-array-subarray.md
new file mode 100644
index 00000000..84f5dae2
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-subarray.md
@@ -0,0 +1,115 @@
+---
+title: "array:subarray()"
+description: "Returns a contiguous sub-array starting at a given position, with optional length."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:subarray(array, start, length?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:subarray()` extracts a portion of an array. The `start` position is 1-based. If `length` is omitted, all members from `start` to the end are returned. If `length` is 0, an empty array is returned. Out-of-range positions or negative lengths raise `err:FOAY0001`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The source array. |
+| `start` | xs:integer | Yes | The 1-based starting position. |
+| `length` | xs:integer? | No | Number of members to include. Defaults to all remaining members. |
+
+## Return value
+
+`array(*)` — the specified sub-array.
+
+## Examples
+
+### Slicing an array
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ b,c,d
+ d,e,f
+
+```
+
+### Pagination with subarray
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (page=2, per-page=3):**
+```xml
+
+ - 4
+ - 5
+ - 6
+
+```
+
+## Notes
+
+- `array:subarray($arr, 1)` returns a copy of the entire array.
+- `array:subarray($arr, 2)` is equivalent to `array:tail($arr)`.
+- `start` must be in the range `1` to `array:size($arr) + 1`; `length` must be non-negative.
+
+## See also
+
+- [array:get()](../xpath-array-get)
+- [array:head()](../xpath-array-head)
+- [array:tail()](../xpath-array-tail)
+- [array:remove()](../xpath-array-remove)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-array-tail.md b/site/content/xslt/functions/xpath-array-tail.md
new file mode 100644
index 00000000..002ae44a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-array-tail.md
@@ -0,0 +1,110 @@
+---
+title: "array:tail()"
+description: "Returns a new array containing all members except the first; raises an error if the array is empty."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "array function"
+syntax: "array:tail(array)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`array:tail()` returns a new array that contains every member of the input array except the first one. If the array has one member, an empty array is returned. If the array is empty, error `err:FOAY0001` is raised. Used together with `array:head()` for recursive array processing.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `array` | array(*) | Yes | The source array. |
+
+## Return value
+
+`array(*)` — a new array with the first member removed; empty array if input had one member.
+
+## Examples
+
+### Popping the first element in a loop
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ a
+ 3
+ b
+
+```
+
+### Recursive array reverse using head and tail
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 5 4 3 2 1
+
+```
+
+## Notes
+
+- Equivalent to `array:subarray($array, 2)`.
+- Raises `err:FOAY0001` for an empty array; guard with `array:size($arr) gt 0`.
+- For efficient list processing, prefer `array:fold-left()` or `array:for-each()` over manual head/tail recursion.
+
+## See also
+
+- [array:head()](../xpath-array-head)
+- [array:get()](../xpath-array-get)
+- [array:subarray()](../xpath-array-subarray)
+- [array:size()](../xpath-array-size)
+- [xsl:array](../xsl-array)
diff --git a/site/content/xslt/functions/xpath-available-environment-variables.md b/site/content/xslt/functions/xpath-available-environment-variables.md
new file mode 100644
index 00000000..3e27d63b
--- /dev/null
+++ b/site/content/xslt/functions/xpath-available-environment-variables.md
@@ -0,0 +1,92 @@
+---
+title: "available-environment-variables()"
+description: "Returns a sequence of strings naming the environment variables that are available to the processor."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "available-environment-variables()"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`available-environment-variables()` returns a sequence of strings, each being the name of an environment variable that the processor is willing to expose. The order of the returned sequence is implementation-defined. If the processor exposes no environment variables, the function returns the empty sequence.
+
+This function is used as a companion to `environment-variable()`: first call `available-environment-variables()` to discover what is exposed, then call `environment-variable()` with a specific name to retrieve its value. This pattern avoids relying on the empty-sequence return from `environment-variable()` as the sole indicator of absence.
+
+The set of available variables may differ between development and production environments. Processors may restrict exposure for security or sandboxing reasons.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:string*` — a sequence of environment variable names that the processor exposes, in implementation-defined order.
+
+## Examples
+
+### Listing available variables
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (varies by environment):**
+```xml
+
+
+
+
+
+```
+
+### Checking whether a specific variable is exposed
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ Mode:
+
+ APP_MODE not available
+
+
+
+```
+
+**Output:**
+```
+APP_MODE not available
+```
+
+## Notes
+
+- The result of `available-environment-variables()` may be an empty sequence even when the OS has environment variables set, if the processor has disabled access.
+- The function is particularly useful in test harnesses that need to adapt behavior based on the current environment without hard-coding variable names.
+- `available-environment-variables()` is a pure function: it has no side effects and returns the same result for repeated calls within a single transformation.
+- In Saxon, this function returns all OS-level environment variables by default. Use Saxon's `-feature` flag to restrict access if needed.
+
+## See also
+
+- [environment-variable()](../xpath-environment-variable)
diff --git a/site/content/xslt/functions/xpath-avg.md b/site/content/xslt/functions/xpath-avg.md
new file mode 100644
index 00000000..4fbf95dc
--- /dev/null
+++ b/site/content/xslt/functions/xpath-avg.md
@@ -0,0 +1,118 @@
+---
+title: "avg()"
+description: "Returns the arithmetic mean of a sequence of numeric values, or the empty sequence if the input is empty."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "numeric function"
+syntax: "avg(sequence)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`avg()` computes the arithmetic mean of all values in a sequence. All items in the sequence must be of a common numeric type (or castable to one). If the sequence is empty, the empty sequence is returned rather than an error.
+
+Duration types (`xs:yearMonthDuration`, `xs:dayTimeDuration`) are also supported.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | xs:anyAtomicType* | Yes | A sequence of numeric or duration values to average. |
+
+## Return value
+
+`xs:anyAtomicType?` — the arithmetic mean of the values, using the promoted common type of the sequence items. Returns the empty sequence when the input is empty.
+
+## Examples
+
+### Average of element values
+
+**Input XML:**
+```xml
+
+
+ 85
+ 92
+ 78
+ 95
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 87.5
+
+```
+
+### Average with grouped data
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 125
+ 190
+
+```
+
+## Notes
+
+- All items in the sequence must be of a compatible numeric type. Mixing `xs:integer` and `xs:string` raises a type error.
+- `avg()` is not available in XSLT 1.0. Use `sum() div count()` as a 1.0 equivalent.
+- For an empty sequence, the function returns the empty sequence (not `NaN` or zero).
+
+## See also
+
+- [abs()](../xpath-abs)
+- [min()](../xpath-min)
+- [max()](../xpath-max)
+- [sum()](../xpath-sum)
diff --git a/site/content/xslt/functions/xpath-base-uri.md b/site/content/xslt/functions/xpath-base-uri.md
new file mode 100644
index 00000000..1318daf6
--- /dev/null
+++ b/site/content/xslt/functions/xpath-base-uri.md
@@ -0,0 +1,100 @@
+---
+title: "base-uri()"
+description: "Returns the base URI of a node as an xs:anyURI, combining the document's URI with any xml:base attributes in scope."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "base-uri(node?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`base-uri()` returns the base URI of a node. The base URI is determined by combining the document URI (from where the document was loaded) with any `xml:base` attributes present on ancestor elements. It follows the XML Base specification (RFC 3986 resolution).
+
+When called without an argument, the context node is used. If the argument is the empty sequence, the empty sequence is returned. If no base URI can be determined, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node()? | No | The node whose base URI is requested. Defaults to the context node. |
+
+## Return value
+
+`xs:anyURI?` — the base URI of the node, or the empty sequence if no base URI is available.
+
+## Examples
+
+### Report base URIs of elements with xml:base
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ http://example.com/docs/
+ http://example.com/docs/chapter1/
+ http://example.com/docs/chapter1/
+
+```
+
+### Use base-uri to resolve relative links
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- If the document was parsed from a string (without a known URI), `base-uri()` may return the empty sequence.
+- `base-uri()` is affected by `xml:base` attributes anywhere in the ancestor chain. The effective base URI is the result of resolving each `xml:base` relative to the one above.
+- To get the base URI of the stylesheet module itself, use `static-base-uri()`.
+- To get the URI of the root document node (ignoring `xml:base`), use `document-uri()`.
+
+## See also
+
+- [document-uri()](../xpath-document-uri)
+- [static-base-uri()](../xpath-static-base-uri)
diff --git a/site/content/xslt/functions/xpath-boolean.md b/site/content/xslt/functions/xpath-boolean.md
new file mode 100644
index 00000000..17a0204b
--- /dev/null
+++ b/site/content/xslt/functions/xpath-boolean.md
@@ -0,0 +1,116 @@
+---
+title: "boolean()"
+description: "Converts any XPath value — node-set, string, number, or boolean — to a boolean according to XPath 1.0 rules."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "boolean function"
+syntax: "boolean(object)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`boolean()` converts its argument to a boolean value following the XPath 1.0 type-conversion rules. The result is always `true` or `false`.
+
+The conversion rules depend on the type of the argument:
+
+- **Node-set:** `true` if the node-set is non-empty, `false` otherwise.
+- **String:** `true` if the string has a length greater than zero, `false` for the empty string `""`.
+- **Number:** `true` if the number is not zero and not `NaN`, `false` for `0` and `NaN`.
+- **Boolean:** returned unchanged.
+
+In practice, most XPath predicates and `xsl:if/@test` expressions perform an implicit boolean conversion, so an explicit call to `boolean()` is needed only when you want to convert a value to a boolean for output or further processing.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `object` | any | Yes | The value to convert. Accepts node-set, string, number, or boolean. |
+
+## Return value
+
+`xs:boolean` — `true` or `false` according to the XPath 1.0 boolean conversion rules.
+
+## Examples
+
+### Convert a string to boolean
+
+**Input XML:**
+```xml
+
+
+ active
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ true
+ false
+
+```
+
+### Convert a number to boolean
+
+**Input XML:**
+```xml
+
+
+ 5
+ 0
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ true
+ false
+
+```
+
+## Notes
+
+- An empty node-set, an empty string, the number `0`, and `NaN` all convert to `false`. Everything else converts to `true`.
+- Calling `boolean()` explicitly is uncommon inside `xsl:if/@test` because XPath already evaluates the test expression as a boolean. Use it when you need to output the literal string `"true"` or `"false"`.
+- `NaN` (produced by operations like `number('abc')`) converts to `false`, not an error.
+- In XSLT 2.0+ the `xs:boolean()` constructor and the `fn:boolean()` function behave similarly but operate on sequences; an empty sequence returns `false`.
+
+## See also
+
+- [not()](../xpath-not)
+- [true()](../xpath-true)
+- [false()](../xpath-false)
diff --git a/site/content/xslt/functions/xpath-ceiling.md b/site/content/xslt/functions/xpath-ceiling.md
new file mode 100644
index 00000000..112a33f4
--- /dev/null
+++ b/site/content/xslt/functions/xpath-ceiling.md
@@ -0,0 +1,121 @@
+---
+title: "ceiling()"
+description: "Returns the smallest integer not less than the argument — equivalent to rounding a number up toward positive infinity."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "numeric function"
+syntax: "ceiling(number)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`ceiling()` returns the smallest integer that is greater than or equal to its argument. It rounds a number **up** toward positive infinity. For positive numbers with a fractional part this means adding enough to reach the next integer; for negative numbers it rounds toward zero.
+
+The argument is first converted to a number using the same rules as `number()`. If the argument is already an integer, it is returned unchanged. Special values (`NaN`, `Infinity`, `-Infinity`) pass through unmodified.
+
+`ceiling()` is the complement of `floor()`. It is commonly used to compute the total number of pages needed to display a set of items, to round monetary amounts up to the next whole unit, or to ensure allocated space is never less than required.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `number` | xs:double | Yes | The number to round up. |
+
+## Return value
+
+`xs:double` — the smallest integer value greater than or equal to the argument.
+
+## Examples
+
+### Total pages needed for a list of items
+
+**Input XML:**
+```xml
+
+
+ - A
+ - B
+ - C
+ - D
+ - E
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 5
+ 3
+
+```
+
+### Ceiling of positive and negative numbers
+
+**Input XML:**
+```xml
+
+
+ 3.2
+ -3.2
+ 4.0
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 4
+ -3
+ 4
+
+```
+
+## Notes
+
+- `ceiling(-3.2)` returns `-3`, not `-4`. The direction is always toward positive infinity.
+- If the argument is `NaN`, `ceiling()` returns `NaN`.
+- If the argument is `Infinity` or `-Infinity`, the same infinity is returned unchanged.
+- Like `floor()`, the return type is `xs:double`, so serialisation may show a trailing `.0` on some processors.
+- When dividing integers, use `ceiling($a div $b)` rather than `ceiling($a) div $b`; the latter rounds the numerator first and can produce incorrect results.
+
+## See also
+
+- [floor()](../xpath-floor)
+- [round()](../xpath-round)
+- [number()](../xpath-number)
diff --git a/site/content/xslt/functions/xpath-codepoints-to-string.md b/site/content/xslt/functions/xpath-codepoints-to-string.md
new file mode 100644
index 00000000..e8023609
--- /dev/null
+++ b/site/content/xslt/functions/xpath-codepoints-to-string.md
@@ -0,0 +1,120 @@
+---
+title: "codepoints-to-string()"
+description: "Constructs a string from a sequence of Unicode codepoint integers, enabling programmatic string assembly from character codes."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "codepoints-to-string(sequence)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`codepoints-to-string()` takes a sequence of integer Unicode codepoints and returns the string formed by the corresponding characters in that order. It is the inverse of `string-to-codepoints()`.
+
+This function is useful when you need to:
+- Construct strings containing characters that are hard to type or embed in XML.
+- Build strings programmatically from computed character codes.
+- Round-trip through codepoint manipulation (e.g., ROT-13, Caesar cipher).
+
+If the sequence is empty, the function returns an empty string. An error is raised if any integer in the sequence is not a valid XML character codepoint (e.g., codepoints in the surrogate range U+D800–U+DFFF).
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | xs:integer* | Yes | A sequence of Unicode codepoint integers. |
+
+## Return value
+
+`xs:string` — the string formed by concatenating the characters for each codepoint in order.
+
+## Examples
+
+### Building a string from codepoints
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Hello
+
+ ©
+
+```
+
+### Applying a simple character shift (Caesar cipher)
+
+**Input XML:**
+```xml
+
+
+ Hello
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Uryyb
+
+```
+
+## Notes
+
+- Codepoints must be valid XML characters. Codepoints 0 (except in some contexts), and the range U+D800–U+DFFF (surrogates) are not valid and will cause a dynamic error.
+- The function accepts a single integer or a sequence of integers interchangeably.
+- Combining with `string-to-codepoints()` enables low-level string transformations without regular expressions.
+- Codepoint 32 is a space, 10 is a newline (`
`), 9 is a tab (` `).
+
+## See also
+
+- [string-to-codepoints()](../xpath-string-to-codepoints)
+- [normalize-unicode()](../xpath-normalize-unicode)
+- [compare()](../xpath-compare)
diff --git a/site/content/xslt/functions/xpath-collection.md b/site/content/xslt/functions/xpath-collection.md
new file mode 100644
index 00000000..e0e4c7fa
--- /dev/null
+++ b/site/content/xslt/functions/xpath-collection.md
@@ -0,0 +1,94 @@
+---
+title: "collection()"
+description: "Returns a sequence of nodes from a named collection, enabling batch processing of multiple XML documents."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "collection(uri?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`collection()` returns a sequence of nodes from a **collection** identified by a URI. A collection is a processor-defined set of nodes — typically a set of XML documents. The most common use in Saxon is to pass a directory URI, which the processor expands to all XML files in that directory.
+
+When called without an argument (or with the empty sequence), the **default collection** is returned. The default collection may be set programmatically via the processor's API.
+
+The exact semantics of the URI are implementation-defined.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `uri` | xs:string? | No | URI identifying the collection. Omit or pass the empty sequence for the default collection. |
+
+## Return value
+
+`node()*` — a sequence of nodes from the collection, typically document nodes.
+
+## Examples
+
+### Process all XML files in a directory (Saxon)
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example with two files):**
+```xml
+
+
+ Learning XSLT
+
+
+ XPath in Practice
+
+
+```
+
+### Merge elements from all collected documents
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The URI syntax for directory collections is Saxon-specific: `file:///path/?select=*.xml` selects XML files; `recurse=yes` enables recursive directory traversal.
+- Saxon also supports catalog-style collection documents (an XML file listing URIs).
+- The order of nodes in the returned sequence is implementation-defined.
+- For a sequence of URIs rather than document nodes, use `uri-collection()`.
+
+## See also
+
+- [uri-collection()](../xpath-uri-collection)
+- [document-uri()](../xpath-document-uri)
diff --git a/site/content/xslt/functions/xpath-compare.md b/site/content/xslt/functions/xpath-compare.md
new file mode 100644
index 00000000..8023f673
--- /dev/null
+++ b/site/content/xslt/functions/xpath-compare.md
@@ -0,0 +1,130 @@
+---
+title: "compare()"
+description: "Compares two strings using a collation and returns -1, 0, or 1 indicating their relative order."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "compare(string1, string2, collation?)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`compare()` performs a three-way comparison of two strings, returning:
+
+- `-1` if `string1` sorts before `string2`
+- `0` if they are equal
+- `1` if `string1` sorts after `string2`
+
+Without a `collation` argument, the default collation (Unicode codepoint order) is used. With a collation URI, language- and locale-sensitive ordering is applied — for example, treating accented and unaccented letters as equivalent, or following locale-specific alphabetical order.
+
+This is the XPath 2.0 equivalent of the three-way comparison operators found in languages like Java (`compareTo`) or C (`strcmp`), and it is the correct function to use when you need ordered comparison rather than just equality.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string1` | xs:string? | Yes | The first string. |
+| `string2` | xs:string? | Yes | The second string. |
+| `collation` | xs:string | No | A collation URI. Defaults to the default collation (typically Unicode codepoint). |
+
+If either argument is an empty sequence, the function returns an empty sequence.
+
+## Return value
+
+`xs:integer?` — `-1`, `0`, or `1`, or the empty sequence if either argument is empty.
+
+## Examples
+
+### Sorting strings and finding the alphabetically first
+
+**Input XML:**
+```xml
+
+
+ banana
+ apple
+ cherry
+ date
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+apple
+
+ -1
+ 1
+ 0
+
+```
+
+### Custom sort using compare() in a function
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+pear
+```
+
+## Notes
+
+- For simple equality testing, use `=` or `eq`. `compare()` is most useful when you need the direction of the difference, not just whether strings are equal.
+- Codepoint collation compares characters by Unicode code number, which does not always match alphabetical order in all languages.
+- Saxon supports IETF BCP 47 language tags as collation URIs (e.g., `http://saxon.sf.net/collation?lang=fr` for French).
+- `compare($a, $b) = 0` is equivalent to `$a = $b` under the same collation.
+
+## See also
+
+- [upper-case()](../xpath-upper-case)
+- [lower-case()](../xpath-lower-case)
+- [codepoints-to-string()](../xpath-codepoints-to-string)
+- [deep-equal()](../xpath-deep-equal)
diff --git a/site/content/xslt/functions/xpath-copy-of.md b/site/content/xslt/functions/xpath-copy-of.md
new file mode 100644
index 00000000..0c828795
--- /dev/null
+++ b/site/content/xslt/functions/xpath-copy-of.md
@@ -0,0 +1,110 @@
+---
+title: "copy-of()"
+description: "Returns a deep copy of all nodes in the sequence, detached from the original document."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "copy-of(sequence)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`copy-of()` returns a deep copy of each node in the sequence. The copies are new nodes that are not part of any existing document tree — they are detached roots. Modifications to the original nodes do not affect the copies, and the copies share no identity with their originals.
+
+This function is the XPath 2.0 function counterpart to the `xsl:copy-of` instruction. It is especially useful inside XPath expressions where you need to pass a fresh copy of a subtree to a function, store it in a variable, or use it as a constructor argument.
+
+Atomic values in the sequence are returned as-is; only node items are copied.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The nodes (and atomic values) to copy. |
+
+## Return value
+
+`item()*` — deep copies of any node items in the sequence; atomic values returned unchanged.
+
+## Examples
+
+### Storing a copy in a variable
+
+**Input XML:**
+```xml
+
+
+ XSLT 2.0 Kay
+ XPath Mangano
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ XSLT 2.0 Kay
+ XPath Mangano
+
+```
+
+### Passing a copy to a function
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ XSLT 2.0 Kay
+
+```
+
+## Notes
+
+- `copy-of()` creates parentless copies; the copies have no document-node parent and no sibling nodes.
+- The function copies all descendants, attributes, namespace nodes, and text content recursively.
+- It differs from `xsl:copy-of` (the instruction) in that it can be used inline in an XPath expression rather than as a standalone instruction.
+- In XSLT 3.0, `snapshot()` serves a similar purpose for streaming contexts where nodes may not be available after the streaming pass ends.
+
+## See also
+
+- [snapshot()](../xpath-snapshot)
+- [deep-equal()](../xpath-deep-equal)
+- [xsl:copy-of](../xsl-copy-of)
diff --git a/site/content/xslt/functions/xpath-current-date-time.md b/site/content/xslt/functions/xpath-current-date-time.md
new file mode 100644
index 00000000..97726d73
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-date-time.md
@@ -0,0 +1,94 @@
+---
+title: "current-dateTime()"
+description: "Returns the current date and time as an xs:dateTime value, fixed for the duration of the transformation."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "current-dateTime()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`current-dateTime()` returns the current date and time as a single `xs:dateTime` value, including the implicit timezone of the processor. The value is **fixed** for the entire transformation, so all calls within a single run return the same timestamp.
+
+It is the most complete timestamp function in XPath 2.0, combining both the date information of `current-date()` and the time information of `current-time()`.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:dateTime` — the current date and time in ISO 8601 form `YYYY-MM-DDTHH:MM:SS.sss+HH:MM`. Stable for the lifetime of the transformation.
+
+## Examples
+
+### Add a full ISO timestamp to the root element
+
+**Input XML:**
+```xml
+
+
+ Alpha
+ Beta
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```xml
+
+ Alpha
+ Beta
+
+```
+
+### Format a human-readable timestamp
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```
+Saturday 18 April 2026 at 14:32
+```
+
+## Notes
+
+- Not available in XSLT 1.0.
+- All three functions — `current-date()`, `current-time()`, and `current-dateTime()` — return consistent values derived from the same instant.
+- Use `xs:date(current-dateTime())` to extract just the date portion, or `xs:time(current-dateTime())` for just the time.
+- Pair with `format-dateTime()` to produce locale-aware output.
+
+## See also
+
+- [current-date()](../xpath-current-date)
+- [current-time()](../xpath-current-time)
+- [format-dateTime()](../xpath-format-date-time)
+- [format-date()](../xpath-format-date)
diff --git a/site/content/xslt/functions/xpath-current-date.md b/site/content/xslt/functions/xpath-current-date.md
new file mode 100644
index 00000000..7f1ab217
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-date.md
@@ -0,0 +1,96 @@
+---
+title: "current-date()"
+description: "Returns the current date as an xs:date value, stable for the duration of the transformation."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "current-date()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`current-date()` returns today's date as an `xs:date` value. The returned value includes the implicit timezone of the processor. Crucially, the value is **fixed** for the entire transformation: all calls within one transformation return the same date, ensuring consistency across the output.
+
+This is the typed-value counterpart to calling `substring-before(string(current-dateTime()), 'T')` in XSLT 1.0.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:date` — the current date in the form `YYYY-MM-DD+HH:MM` (with timezone offset). The date is stable for the lifetime of the transformation.
+
+## Examples
+
+### Stamp a document with today's date
+
+**Input XML:**
+```xml
+
+
+ Annual Summary
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```xml
+
+ 2026-04-18+01:00
+ Annual Summary
+
+```
+
+### Format today's date for display
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```
+Saturday, 18 April 2026
+```
+
+## Notes
+
+- `current-date()` is not available in XSLT 1.0.
+- The value includes the processor's implicit timezone. Use `adjust-date-to-timezone()` to convert to a different offset.
+- To extract parts of the date, use `year-from-date()`, `month-from-date()`, or `day-from-date()`.
+- For a combined date and time, use `current-dateTime()`.
+
+## See also
+
+- [current-time()](../xpath-current-time)
+- [current-dateTime()](../xpath-current-date-time)
+- [year-from-date()](../xpath-year-from-date)
+- [month-from-date()](../xpath-month-from-date)
+- [day-from-date()](../xpath-day-from-date)
+- [format-date()](../xpath-format-date)
diff --git a/site/content/xslt/functions/xpath-current-group.md b/site/content/xslt/functions/xpath-current-group.md
new file mode 100644
index 00000000..b821d4d8
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-group.md
@@ -0,0 +1,102 @@
+---
+title: "current-group()"
+description: "Returns the sequence of items in the current group inside an xsl:for-each-group instruction."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "current-group()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`current-group()` returns all the items that belong to the current group within an `` instruction. It is only meaningful inside `xsl:for-each-group` — outside that instruction, the result is implementation-defined (typically the empty sequence).
+
+Paired with `current-grouping-key()`, it gives you full access to both the grouping criterion and the grouped items.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`item()*` — the sequence of items in the current group.
+
+## Examples
+
+### Summarise sales by region
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 2 250
+ 2 380
+ 1 300
+
+```
+
+### Wrap each group in a container element
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `current-group()` is only valid inside `xsl:for-each-group`. Using it elsewhere is an error or returns the empty sequence depending on the processor.
+- The items in `current-group()` are a subset of the `select` expression of the enclosing `xsl:for-each-group`, in document order.
+- The context item inside `xsl:for-each-group` is the **first item** of the current group; `current-group()` gives you all items.
+
+## See also
+
+- [current-grouping-key()](../xpath-current-grouping-key)
+- [xsl:for-each-group](../xsl-for-each-group)
diff --git a/site/content/xslt/functions/xpath-current-grouping-key.md b/site/content/xslt/functions/xpath-current-grouping-key.md
new file mode 100644
index 00000000..6d7bd775
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-grouping-key.md
@@ -0,0 +1,110 @@
+---
+title: "current-grouping-key()"
+description: "Returns the grouping key of the current group inside an xsl:for-each-group instruction."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "current-grouping-key()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`current-grouping-key()` returns the value of the grouping key for the current group within an `` instruction. The type and value of the key corresponds to the result of evaluating the `group-by`, `group-adjacent`, `group-starting-with`, or `group-ending-with` attribute for the representative item of the current group.
+
+It is only meaningful inside `xsl:for-each-group`. Outside that instruction, the result is implementation-defined.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:anyAtomicType?` — the grouping key of the current group, or the empty sequence when used with `group-starting-with` or `group-ending-with`.
+
+## Examples
+
+### Group and label by category
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ - XSLT Guide
+ - XML Handbook
+
+
+ - Tablet
+ - Laptop
+
+
+```
+
+### Use the grouping key in a heading
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- For `group-starting-with` and `group-ending-with`, `current-grouping-key()` returns the empty sequence because these grouping methods do not use a key expression.
+- `current-grouping-key()` is only valid inside `xsl:for-each-group`. Using it elsewhere is an error.
+- When multiple keys are produced by a sequence-valued `group-by`, the key for the current group is the specific value that identified this group.
+
+## See also
+
+- [current-group()](../xpath-current-group)
+- [xsl:for-each-group](../xsl-for-each-group)
diff --git a/site/content/xslt/functions/xpath-current-merge-group.md b/site/content/xslt/functions/xpath-current-merge-group.md
new file mode 100644
index 00000000..3dfa108a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-merge-group.md
@@ -0,0 +1,117 @@
+---
+title: "current-merge-group()"
+description: "Returns the sequence of items in the current merge group inside an xsl:merge-action block."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "current-merge-group(source?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`current-merge-group()` is used inside the `xsl:merge-action` child of an `xsl:merge` instruction. It returns the sequence of items from the current merge group — that is, all items from one or more merge sources that share the same current merge key.
+
+When `xsl:merge` processes multiple input streams simultaneously, it groups corresponding items by their computed merge key. Inside `xsl:merge-action`, `current-merge-group()` without an argument returns all items from all sources in the current group. When a `source` argument is supplied (the value of a `for-each-source` attribute or a source name), the function returns items only from that specific merge source.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `source` | xs:string | No | The name of the merge source to restrict the group to. Omit to get items from all sources. |
+
+## Return value
+
+`item()*` — the items in the current merge group, optionally restricted to a named source.
+
+## Examples
+
+### Merging two sorted lists
+
+**Input XML (file1.xml):**
+```xml
+
+
+ - Alpha from source1
+ - Beta from source1
+
+```
+
+**Input XML (file2.xml):**
+```xml
+
+
+ - Alpha from source2
+ - Gamma from source2
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ - Alpha from source1
+ - Alpha from source2
+
+
+ - Beta from source1
+
+
+ - Gamma from source2
+
+
+```
+
+### Reading from a specific source
+
+**Stylesheet snippet:**
+```xml
+
+
+
+
+
+
+```
+
+## Notes
+
+- `current-merge-group()` is only valid inside the `xsl:merge-action` element; using it elsewhere raises a static error.
+- Without an argument, it returns items from all named merge sources combined.
+- The merge sources must provide pre-sorted input or declare sort keys via `xsl:merge-key` for `xsl:merge` to operate correctly.
+- `current-merge-group()` and `current-merge-key()` are the two functions designed specifically for use inside `xsl:merge-action`.
+
+## See also
+
+- [current-merge-key()](../xpath-current-merge-key)
+- [xsl:use-accumulators](../xsl-use-accumulators)
diff --git a/site/content/xslt/functions/xpath-current-merge-key.md b/site/content/xslt/functions/xpath-current-merge-key.md
new file mode 100644
index 00000000..0aa06d3c
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-merge-key.md
@@ -0,0 +1,123 @@
+---
+title: "current-merge-key()"
+description: "Returns the current merge key value inside an xsl:merge-action block."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "current-merge-key()"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`current-merge-key()` returns the value of the merge key for the current group being processed inside an `xsl:merge-action` block. When `xsl:merge` groups items from one or more sources by their computed key, `current-merge-key()` provides the key value shared by all items in the current group.
+
+The returned value is an atomic value or a sequence of atomic values corresponding to the `xsl:merge-key` expressions declared in the merge sources. When multiple keys are declared (composite keys), the function returns a sequence of values — one per key component — in declaration order.
+
+`current-merge-key()` is the merge equivalent of `current-grouping-key()` from `xsl:for-each-group`.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:anyAtomicType+` — the merge key value(s) for the current group.
+
+## Examples
+
+### Displaying the merge key in output
+
+**Input XML (employees.xml):**
+```xml
+
+
+
+
+
+
+```
+
+**Input XML (salaries.xml):**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Using the key in a conditional
+
+**Stylesheet snippet:**
+```xml
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `current-merge-key()` is only valid inside the `xsl:merge-action` element.
+- For composite merge keys (multiple `xsl:merge-key` declarations), the function returns a sequence of atomic values in declaration order.
+- The key type is determined by the key expression; string, numeric, date, and other atomic types are all supported.
+- This function is the merge counterpart to `current-grouping-key()` used with `xsl:for-each-group`.
+
+## See also
+
+- [current-merge-group()](../xpath-current-merge-group)
+- [xsl:use-accumulators](../xsl-use-accumulators)
diff --git a/site/content/xslt/functions/xpath-current-output-uri.md b/site/content/xslt/functions/xpath-current-output-uri.md
new file mode 100644
index 00000000..8ce8ff1c
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-output-uri.md
@@ -0,0 +1,97 @@
+---
+title: "current-output-uri()"
+description: "Returns the URI of the current result document being written inside an xsl:result-document instruction."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "current-output-uri()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`current-output-uri()` returns the URI of the result document currently being written — the `href` value of the enclosing `` instruction. Outside an `xsl:result-document`, it returns the empty sequence.
+
+This is useful for embedding a document's own URI as metadata within itself, logging which file is being generated, or constructing relative cross-references between generated documents.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:anyURI?` — the URI of the current result document, or the empty sequence when called outside `xsl:result-document`.
+
+## Examples
+
+### Embed the output URI in each generated document
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (ch1.xml):**
+```xml
+
+ Introduction
+
+```
+
+### Log generated file names to the principal output
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Returns the empty sequence when called in the principal result tree (outside any `xsl:result-document`).
+- The returned URI is the value of the `href` attribute of the enclosing `xsl:result-document`, resolved against the static base URI if it is relative.
+- Useful for generating self-referential metadata in split-document outputs.
+
+## See also
+
+- [static-base-uri()](../xpath-static-base-uri)
+- [document-uri()](../xpath-document-uri)
diff --git a/site/content/xslt/functions/xpath-current-time.md b/site/content/xslt/functions/xpath-current-time.md
new file mode 100644
index 00000000..70d0ab23
--- /dev/null
+++ b/site/content/xslt/functions/xpath-current-time.md
@@ -0,0 +1,94 @@
+---
+title: "current-time()"
+description: "Returns the current time as an xs:time value, stable and fixed for the duration of the transformation."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "current-time()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`current-time()` returns the current time as an `xs:time` value, including the implicit timezone of the processor. Like `current-date()` and `current-dateTime()`, the value is **fixed** for the entire transformation: repeated calls return the same time, guaranteeing a consistent timestamp throughout the output.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:time` — the current time in the form `HH:MM:SS.sss+HH:MM` (with timezone offset). Stable for the lifetime of the transformation.
+
+## Examples
+
+### Embed the generation time in output
+
+**Input XML:**
+```xml
+
+
+ - First item
+ - Second item
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```xml
+
+ - First item
+ - Second item
+
+```
+
+### Format the current time for display
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```
+14:32:07
+```
+
+## Notes
+
+- Not available in XSLT 1.0.
+- The value includes the processor's implicit timezone. Pair with `adjust-time-to-timezone()` to normalise to UTC or another offset.
+- To extract individual components, use `hours-from-time()`, `minutes-from-time()`, or `seconds-from-time()`.
+- For a combined date and time, use `current-dateTime()`.
+
+## See also
+
+- [current-date()](../xpath-current-date)
+- [current-dateTime()](../xpath-current-date-time)
+- [hours-from-time()](../xpath-hours-from-time)
+- [minutes-from-time()](../xpath-minutes-from-time)
+- [seconds-from-time()](../xpath-seconds-from-time)
+- [format-time()](../xpath-format-time)
diff --git a/site/content/xslt/functions/xpath-day-from-date.md b/site/content/xslt/functions/xpath-day-from-date.md
new file mode 100644
index 00000000..ecc5a8e8
--- /dev/null
+++ b/site/content/xslt/functions/xpath-day-from-date.md
@@ -0,0 +1,105 @@
+---
+title: "day-from-date()"
+description: "Extracts the day-of-month component from an xs:date value as an xs:integer in the range 1–31."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "day-from-date(date)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`day-from-date()` returns the day-of-month component of an `xs:date` value as an `xs:integer` between 1 and 31. If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `date` | xs:date? | Yes | The date value from which to extract the day. |
+
+## Return value
+
+`xs:integer?` — integer from 1 to 31 representing the day of the month, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Display a formatted date with separate components
+
+**Input XML:**
+```xml
+
+
+ 2026-04-18
+ 2026-05-18
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ 18
+ 4
+ 2026
+
+
+ 18
+ 5
+ 2026
+
+
+```
+
+### Find events on the 1st of any month
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The argument must be typed as `xs:date`. Cast string values with `xs:date(.)` or `xs:date(@attr)`.
+- Returns 1–31 depending on the month; it does not validate whether the day is valid for the given month (that is enforced when constructing the `xs:date` value).
+- For `xs:dateTime` values, use `day-from-dateTime()`.
+
+## See also
+
+- [year-from-date()](../xpath-year-from-date)
+- [month-from-date()](../xpath-month-from-date)
+- [current-date()](../xpath-current-date)
diff --git a/site/content/xslt/functions/xpath-deep-equal.md b/site/content/xslt/functions/xpath-deep-equal.md
new file mode 100644
index 00000000..5c7e5308
--- /dev/null
+++ b/site/content/xslt/functions/xpath-deep-equal.md
@@ -0,0 +1,107 @@
+---
+title: "deep-equal()"
+description: "Returns true if two sequences are deeply equal: same items in the same order with equal node identity or atomic values."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "deep-equal(sequence1, sequence2, collation?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`deep-equal()` compares two sequences item by item. Two sequences are deeply equal if they have the same length and each pair of corresponding items is deeply equal. For atomic values, deep equality uses the same comparison as `=` with type promotion. For nodes, deep equality means the nodes have the same kind, name, and — recursively — the same children, attributes, and text content.
+
+The optional `collation` argument controls string comparison. When omitted, the default collation is used. This makes `deep-equal()` suitable for locale-aware comparisons of mixed sequences containing strings.
+
+`deep-equal()` never raises an error for incompatible types: comparing an integer to a string returns `false` rather than a type error, which distinguishes it from the `=` operator.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence1` | item()* | Yes | The first sequence to compare. |
+| `sequence2` | item()* | Yes | The second sequence to compare. |
+| `collation` | xs:string | No | URI of the collation used for string comparison. |
+
+## Return value
+
+`xs:boolean` — `true` if the sequences are deeply equal, `false` otherwise.
+
+## Examples
+
+### Comparing two element subtrees
+
+**Input XML:**
+```xml
+
+
+ 1 2
+ 1 2
+ 1 3
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ true
+ false
+
+```
+
+### Comparing sequences of atomic values
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+true
+false
+```
+
+## Notes
+
+- `deep-equal()` compares attributes regardless of document order for element nodes. Two elements with the same attributes in a different order are still deeply equal.
+- Namespace nodes, processing instructions, and comments are included in the comparison when they are present in the node's children.
+- The function is particularly useful in unit tests and validation stylesheets where you need to assert that a transformation produced an expected XML structure.
+- An empty sequence is deeply equal only to another empty sequence.
+
+## See also
+
+- [empty()](../xpath-empty)
+- [count()](../xpath-count)
+- [exactly-one()](../xpath-exactly-one)
diff --git a/site/content/xslt/functions/xpath-distinct-values.md b/site/content/xslt/functions/xpath-distinct-values.md
new file mode 100644
index 00000000..829da72c
--- /dev/null
+++ b/site/content/xslt/functions/xpath-distinct-values.md
@@ -0,0 +1,130 @@
+---
+title: "distinct-values()"
+description: "Returns a sequence containing only the distinct values from the input sequence, removing duplicates using value equality."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "distinct-values(sequence, collation?)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`distinct-values()` removes duplicate atomic values from a sequence, retaining one representative from each group of equal values. The order of retained values follows the order of first occurrence in the input sequence.
+
+Equality is determined by value semantics (not identity): for strings, the default Unicode codepoint collation is used unless a different `collation` URI is provided; for numeric types, numeric equality applies (so `1` and `1.0` are equal).
+
+The function works on atomic values only. If the input contains nodes, their typed values (strings) are compared — not the nodes themselves.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | xs:anyAtomicType* | Yes | The sequence to deduplicate. |
+| `collation` | xs:string | No | A collation URI for string comparison. |
+
+## Return value
+
+`xs:anyAtomicType*` — the sequence with duplicates removed, preserving first-occurrence order.
+
+## Examples
+
+### Getting unique categories
+
+**Input XML:**
+```xml
+
+
+ Apple
+ Carrot
+ Banana
+ Rice
+ Broccoli
+ Cherry
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Fruit
+ Grain
+ Vegetable
+
+```
+
+### Counting unique authors across articles
+
+**Input XML:**
+```xml
+
+
+ Article 1
+ Article 2
+ Article 3
+ Article 4
+ Article 5
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Alice
+ Bob
+ Carol
+
+
+```
+
+## Notes
+
+- `distinct-values()` operates on atomic values, not nodes. If you apply it to element nodes, their string values are compared. If you need to group and deduplicate by element identity, use `xsl:for-each-group` with `group-by`.
+- For grouping with the ability to access all members of each group, `xsl:for-each-group` is more appropriate than `distinct-values()`.
+- Numeric type coercion applies: `distinct-values((1, 1.0, 1e0))` may return just one item, since all are numerically equal.
+- The order of results is the order of first occurrence — it is not sorted. Add `xsl:sort` or `sort()` to sort the output.
+
+## See also
+
+- [xsl:for-each-group](../xsl-for-each-group)
+- [index-of()](../xpath-index-of)
+- [count()](../xpath-count)
diff --git a/site/content/xslt/functions/xpath-document-uri.md b/site/content/xslt/functions/xpath-document-uri.md
new file mode 100644
index 00000000..6352bb41
--- /dev/null
+++ b/site/content/xslt/functions/xpath-document-uri.md
@@ -0,0 +1,86 @@
+---
+title: "document-uri()"
+description: "Returns the URI of the document node that contains the given node, as an xs:anyURI."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "document-uri(node?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`document-uri()` returns the URI used to load the document containing the given node. Unlike `base-uri()`, it returns the URI of the **document node** itself and is not affected by `xml:base` attributes on descendant elements.
+
+When called without an argument, the context node is used. If the argument is the empty sequence or the node has no document URI (e.g., it was constructed in memory), the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node()? | No | The node whose document URI is requested. Defaults to the context node. |
+
+## Return value
+
+`xs:anyURI?` — the URI of the document node, or the empty sequence if no URI is available.
+
+## Examples
+
+### Report the document URI of a loaded document
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```xml
+
+ file:///data/input.xml
+
+```
+
+### Load and track multiple documents
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `document-uri()` returns the URI of the **document root**, not an element's base URI. For the effective base URI (considering `xml:base`), use `base-uri()`.
+- For nodes created via `parse-xml()` or result tree fragments, the document URI is typically absent (empty sequence).
+- The function was introduced in XPath 2.0 and is not available in XSLT 1.0.
+
+## See also
+
+- [base-uri()](../xpath-base-uri)
+- [static-base-uri()](../xpath-static-base-uri)
+- [parse-xml()](../xpath-parse-xml)
diff --git a/site/content/xslt/functions/xpath-document.md b/site/content/xslt/functions/xpath-document.md
new file mode 100644
index 00000000..ff091b58
--- /dev/null
+++ b/site/content/xslt/functions/xpath-document.md
@@ -0,0 +1,126 @@
+---
+title: "document()"
+description: "Loads an external XML document by URI and returns its root node as a node-set, enabling multi-document transformations in XSLT 1.0."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "document(uri, node?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`document()` retrieves an external XML document and returns it as a node-set containing the document root. This is the primary mechanism in XSLT 1.0 for accessing data from multiple sources within a single transformation.
+
+The first argument can be:
+- A **string** URI — the document at that URI is loaded and returned as a single-item node-set.
+- A **node-set** — each node is converted to its string value (treated as a URI), the corresponding documents are loaded, and their root nodes are returned as a combined node-set.
+
+The optional second argument is a node from which the base URI for resolving relative URIs is taken. If omitted, relative URIs are resolved against the base URI of the stylesheet.
+
+Calling `document('')` is a special idiom: it returns the root of the **stylesheet document itself**, allowing stylesheet data to be embedded as XML and accessed from templates.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `uri` | xs:string or node-set | Yes | URI of the external document, or a node-set of URI-valued nodes. |
+| `node` | node-set | No | Node whose base URI is used to resolve relative URIs in the first argument. |
+
+## Return value
+
+`node-set` — the root nodes of the loaded document(s).
+
+## Examples
+
+### Load an external lookup document
+
+**External file: `colors.xml`**
+```xml
+
+
+ Red
+ Green
+ Blue
+
+```
+
+**Input XML:**
+```xml
+
+
+ - Apple
+ - Leaf
+ - Sky
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Apple
+ - Leaf
+ - Sky
+
+```
+
+### Embed data in the stylesheet using document('')
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The behavior when the referenced document cannot be found is processor-specific: some processors raise a fatal error, others return an empty node-set. Check processor documentation.
+- `document('')` returns the stylesheet document; combine with an XPath expression to navigate to embedded data elements.
+- Relative URIs are resolved against the **stylesheet** base URI by default, not the source document URI. Use the second argument to change the base.
+- In XSLT 2.0+, `document()` is superseded by the `fn:doc()` and `fn:collection()` functions, which integrate with XPath 2.0's type system.
+
+## See also
+
+- [xsl:import](../xsl-import)
+- [xsl:include](../xsl-include)
diff --git a/site/content/xslt/functions/xpath-element-available.md b/site/content/xslt/functions/xpath-element-available.md
new file mode 100644
index 00000000..22aeb983
--- /dev/null
+++ b/site/content/xslt/functions/xpath-element-available.md
@@ -0,0 +1,106 @@
+---
+title: "element-available()"
+description: "Returns true if the named XSLT instruction or extension element is supported by the processor, enabling portable fallback branches."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "element-available(name)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`element-available()` tests whether the XSLT processor supports a named instruction element and returns a boolean. The argument is a string containing a QName; if the QName is in the `xsl:` namespace, it tests for a standard XSLT instruction. If it is in another namespace, it tests for a processor-specific extension element.
+
+The function is intended for use inside `xsl:choose`/`xsl:when` or `xsl:if` to branch between implementations depending on what the current processor supports. Combined with `xsl:fallback`, it provides a portable way to use extension elements with graceful degradation.
+
+Only elements that appear as **children of the stylesheet** (i.e. XSLT instructions and extension elements, not result elements) are tested. Testing for an arbitrary user-defined element name that is not an instruction always returns `false`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:string | Yes | A QName string naming the element to test. The namespace prefix must be in scope. |
+
+## Return value
+
+`xs:boolean` — `true` if the element is available, `false` otherwise.
+
+## Examples
+
+### Test for a standard XSLT instruction
+
+**Input XML:**
+```xml
+
+- A
- B
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ true
+ false
+
+```
+
+### Guard use of an extension element
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+ Multi-document output supported.
+
+
+ Multi-document output not supported; writing single file.
+
+
+
+
+
+```
+
+## Notes
+
+- `element-available()` only tests **XSLT instructions** and **extension elements**. It does not test for result element names (elements in no namespace or a non-XSLT namespace that become part of the output tree).
+- The prefix in the QName string must be declared in the stylesheet's namespace context; otherwise the function raises an error.
+- Standard XSLT 1.0 instructions (e.g. `xsl:for-each`, `xsl:if`, `xsl:choose`) always return `true` in a conformant XSLT 1.0 processor.
+- In XSLT 2.0+, the function is unchanged. It can be used to test for XSLT 2.0 instructions (e.g. `xsl:for-each-group`) when running under a processor that may be in XSLT 1.0 compatibility mode.
+
+## See also
+
+- [function-available()](../xpath-function-available)
+- [system-property()](../xpath-system-property)
+- [xsl:fallback](../xsl-fallback)
diff --git a/site/content/xslt/functions/xpath-empty.md b/site/content/xslt/functions/xpath-empty.md
new file mode 100644
index 00000000..160f3cfe
--- /dev/null
+++ b/site/content/xslt/functions/xpath-empty.md
@@ -0,0 +1,107 @@
+---
+title: "empty()"
+description: "Returns true if the sequence has zero items, and false if it contains one or more items."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "empty(sequence)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`empty()` tests whether a sequence contains no items. It is the logical complement of `exists()`: `empty($s)` is equivalent to `not(exists($s))` and to `count($s) = 0`, but is more readable and may be more efficient because the processor can stop as soon as it finds any item.
+
+The sequence argument may be any XPath expression — a node selection, a function result, or a constructed sequence.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence to test. |
+
+## Return value
+
+`xs:boolean` — `true` if the sequence is empty, `false` otherwise.
+
+## Examples
+
+### Checking for missing child elements
+
+**Input XML:**
+```xml
+
+
+ Alpha xml
+ Beta
+ Gamma
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alpha
+ Beta
+ Gamma
+
+```
+
+### Providing a default when a sequence is empty
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+ No active items found.
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `empty($seq)` is semantically equivalent to `not($seq)` for sequences, but is preferred for clarity when working with typed sequences.
+- For node selections, `empty(//foo)` is more readable than `not(//foo)`, especially in predicate contexts.
+- `empty()` short-circuits: it does not need to evaluate the entire sequence; it stops at the first item.
+- Use `exists()` to test the positive case; avoid double negation with `not(empty(...))`.
+
+## See also
+
+- [exists()](../xpath-exists)
+- [count()](../xpath-count)
+- [zero-or-one()](../xpath-zero-or-one)
diff --git a/site/content/xslt/functions/xpath-ends-with.md b/site/content/xslt/functions/xpath-ends-with.md
new file mode 100644
index 00000000..449a6995
--- /dev/null
+++ b/site/content/xslt/functions/xpath-ends-with.md
@@ -0,0 +1,102 @@
+---
+title: "ends-with()"
+description: "Returns true if the first string ends with the second string, using optional collation for comparison."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "ends-with(string, suffix)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`ends-with()` tests whether the string in the first argument ends with the string in the second argument. It returns `true` if the suffix matches, `false` otherwise.
+
+The comparison uses codepoint-by-codepoint equality by default (same as XPath's `=` operator on strings). In XPath 2.0 a third `collation` argument is allowed for locale-sensitive suffix testing, though most processors default to the Unicode codepoint collation.
+
+If either argument is an empty string `""`, special rules apply: any string ends with `""` (always `true`), and `""` ends with `""` (also `true`).
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | The string to test. |
+| `suffix` | xs:string? | Yes | The suffix to look for at the end of `string`. |
+
+## Return value
+
+`xs:boolean` — `true` if `string` ends with `suffix`, `false` otherwise.
+
+## Examples
+
+### Filtering files by extension
+
+**Input XML:**
+```xml
+
+
+ report.pdf
+ data.xml
+ summary.pdf
+ stylesheet.xsl
+ notes.txt
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ report.pdf
+ summary.pdf
+
+```
+
+### Checking namespace URIs
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `ends-with()` was introduced in XPath 2.0. In XPath 1.0 there is no built-in equivalent; the workaround is `substring($s, string-length($s) - string-length($suffix) + 1) = $suffix`.
+- The comparison is case-sensitive by default. For case-insensitive suffix testing, normalize both strings with `lower-case()` first.
+- An empty `suffix` always returns `true`. An empty `string` with a non-empty `suffix` returns `false`.
+- `starts-with()` (available in both XPath 1.0 and 2.0) is the complementary function for prefix testing.
+
+## See also
+
+- [starts-with()](../xpath-starts-with)
+- [contains()](../xpath-contains)
+- [substring()](../xpath-substring)
+- [lower-case()](../xpath-lower-case)
diff --git a/site/content/xslt/functions/xpath-environment-variable.md b/site/content/xslt/functions/xpath-environment-variable.md
new file mode 100644
index 00000000..c401b859
--- /dev/null
+++ b/site/content/xslt/functions/xpath-environment-variable.md
@@ -0,0 +1,99 @@
+---
+title: "environment-variable()"
+description: "Returns the value of the named environment variable as a string, or the empty sequence if unavailable."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "environment-variable(name)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`environment-variable()` retrieves the value of a named operating-system or processor-defined environment variable. The function returns the value as a string if the variable is set and accessible, or the empty sequence if it is not available.
+
+Processors are not required to expose any particular environment variables, and they may choose to expose none at all for security reasons. Use `available-environment-variables()` to discover which variables are accessible before calling this function. The function raises no error when a variable is absent — it simply returns the empty sequence, which can be tested with `exists()` or `empty()`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:string | Yes | The name of the environment variable to retrieve. |
+
+## Return value
+
+`xs:string?` — the value of the environment variable, or the empty sequence if the variable is not set or not accessible.
+
+## Examples
+
+### Using an environment variable as a default
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (on a Unix system):**
+```xml
+
+ /home/username
+ username
+
+```
+
+### Checking availability before reading
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ Environment:
+
+
+ APP_ENV not set — using defaults
+
+
+
+
+```
+
+**Output:**
+```
+APP_ENV not set — using defaults
+```
+
+## Notes
+
+- Whether environment variables are accessible depends entirely on the processor implementation and security configuration. Saxon exposes OS environment variables by default, but this can be disabled.
+- The function is read-only; there is no mechanism in XPath/XSLT to set environment variables.
+- Environment variable names are case-sensitive on Unix-like systems and case-insensitive on Windows.
+- For production stylesheets, prefer XSLT parameters (`xsl:param`) over environment variables, as parameters are more portable and explicit.
+
+## See also
+
+- [available-environment-variables()](../xpath-available-environment-variables)
diff --git a/site/content/xslt/functions/xpath-error.md b/site/content/xslt/functions/xpath-error.md
new file mode 100644
index 00000000..96d4f7df
--- /dev/null
+++ b/site/content/xslt/functions/xpath-error.md
@@ -0,0 +1,109 @@
+---
+title: "error()"
+description: "Raises a dynamic error with an optional error code, description message, and error object."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "error(code?, description?, object?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`error()` raises a dynamic error unconditionally when evaluated. The transformation is aborted unless the error is caught by an `xsl:try/xsl:catch` block (XSLT 3.0). The function is useful for asserting preconditions, documenting unreachable code branches, and raising structured errors with well-defined error codes.
+
+All three arguments are optional. When called with no arguments, a generic error (`FOER0000`) is raised. When `code` is supplied it must be a `QName` such as `QName('http://example.com/errors', 'e:InvalidInput')`. The `description` is a human-readable string. The `object` is an arbitrary item sequence attached to the error for diagnostic purposes.
+
+Because `error()` never returns a value, it can be used in any XPath context, including the middle of a conditional expression.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `code` | xs:QName? | No | A QName identifying the error type; defaults to `FOER0000`. |
+| `description` | xs:string? | No | A human-readable description of the error. |
+| `object` | item()* | No | Arbitrary diagnostic data attached to the error. |
+
+## Return value
+
+`error()` never returns; it always raises a dynamic error.
+
+## Examples
+
+### Guarding an invalid input
+
+**Input XML:**
+```xml
+
+
+ -5
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (transformation aborted):**
+```
+Dynamic error: Age must be non-negative, got: -5
+```
+
+### Catching an error in XSLT 3.0
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Resource missing
+
+```
+
+## Notes
+
+- `error()` with no arguments raises `FOER0000`; this is the XPath equivalent of an unspecified runtime exception.
+- In XSLT 1.0, `xsl:message terminate="yes"` is the closest equivalent since `error()` is not available.
+- The `object` argument is accessible as `$err:value` inside an `xsl:catch` block in XSLT 3.0.
+- `error()` is typed as returning `none`, which means it is type-compatible with any return type and can appear in the branch of an `if` expression without causing a type error.
+
+## See also
+
+- [xsl:message](../xsl-message)
+- [trace()](../xpath-trace)
+- [exactly-one()](../xpath-exactly-one)
diff --git a/site/content/xslt/functions/xpath-exactly-one.md b/site/content/xslt/functions/xpath-exactly-one.md
new file mode 100644
index 00000000..bae72d29
--- /dev/null
+++ b/site/content/xslt/functions/xpath-exactly-one.md
@@ -0,0 +1,109 @@
+---
+title: "exactly-one()"
+description: "Asserts that the sequence contains exactly one item; raises a dynamic error if the sequence has zero or more than one item."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "exactly-one(sequence)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`exactly-one()` is a cardinality assertion function. It returns its argument unchanged if the sequence contains exactly one item, and raises a dynamic error (`FORG0005`) if the sequence is empty or contains more than one item.
+
+Use `exactly-one()` to make cardinality assumptions explicit in your stylesheets. Rather than silently processing zero or multiple nodes when you expect exactly one, the function causes a clear error with a meaningful location. This is particularly valuable for enforcing schema-like constraints when schema validation is not available.
+
+The function is purely an assertion; it performs no transformation of the data and has no effect on correct input.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence that must contain exactly one item. |
+
+## Return value
+
+`item()` — the single item from the sequence, unchanged. Raises `FORG0005` if the sequence does not contain exactly one item.
+
+## Examples
+
+### Asserting a unique key lookup
+
+**Input XML:**
+```xml
+
+
+ Alice
+ Bob
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice
+
+```
+
+### Catching the error with try/catch (XSLT 3.0)
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+ No unique employee found:
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ No unique employee found: ...
+
+```
+
+## Notes
+
+- The error code raised is `err:FORG0005` defined in the XPath/XQuery Functions and Operators specification.
+- `exactly-one()` is equivalent to writing `$seq[1][last() = 1]` as a guard, but is cleaner and raises a standard error code.
+- In XSLT 2.0 function signatures, the `item()` return type implicitly asserts exactly one item; `exactly-one()` makes that same assertion in an expression context.
+- For sequences that may be empty, use `zero-or-one()` instead; for sequences that must be non-empty, use `one-or-more()`.
+
+## See also
+
+- [zero-or-one()](../xpath-zero-or-one)
+- [one-or-more()](../xpath-one-or-more)
+- [error()](../xpath-error)
+- [deep-equal()](../xpath-deep-equal)
diff --git a/site/content/xslt/functions/xpath-exists.md b/site/content/xslt/functions/xpath-exists.md
new file mode 100644
index 00000000..31080301
--- /dev/null
+++ b/site/content/xslt/functions/xpath-exists.md
@@ -0,0 +1,110 @@
+---
+title: "exists()"
+description: "Returns true if the sequence contains at least one item, and false if it is empty."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "exists(sequence)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`exists()` tests whether a sequence is non-empty. It returns `true` as soon as it finds at least one item, making it potentially more efficient than `count($seq) gt 0` because it can stop evaluation early. It is the complement of `empty()`.
+
+While XSLT 1.0 used boolean coercion of node sets (e.g., `if ($nodes)`) to test for existence, `exists()` is the explicit and type-safe XPath 2.0 way to do the same.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence to test. |
+
+## Return value
+
+`xs:boolean` — `true` if the sequence contains one or more items, `false` if it is empty.
+
+## Examples
+
+### Conditional output based on element existence
+
+**Input XML:**
+```xml
+
+
+
+ Introduction
+ Some text here.
+
+ Source: Wikipedia
+
+
+
+ Main Content
+ Body text.
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:** The intro section renders an `` with footnotes; the body section does not.
+
+### Checking whether a variable holds a result
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+ item(s) out of stock.
+
+
+
+
+```
+
+## Notes
+
+- `exists($seq)` is equivalent to `count($seq) gt 0` but preferred for readability and potential performance benefits.
+- In XPath 1.0, existence was tested by relying on the boolean value of a node-set: `if ($nodes)`. In XPath 2.0, `exists()` makes the intent explicit and works correctly for all sequence types.
+- Do not confuse `exists()` with `not(empty($seq))` — they are logically identical, but `exists()` is more readable.
+- For constraining cardinality rather than just testing, see `zero-or-one()`, `one-or-more()`, and `exactly-one()`.
+
+## See also
+
+- [empty()](../xpath-empty)
+- [count()](../xpath-count)
+- [one-or-more()](../xpath-one-or-more)
diff --git a/site/content/xslt/functions/xpath-false.md b/site/content/xslt/functions/xpath-false.md
new file mode 100644
index 00000000..3add84ac
--- /dev/null
+++ b/site/content/xslt/functions/xpath-false.md
@@ -0,0 +1,124 @@
+---
+title: "false()"
+description: "Returns the boolean value false. Used in XPath expressions where an explicit boolean false literal is required."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "boolean function"
+syntax: "false()"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`false()` returns the boolean literal `false`. Like `true()`, it exists because XPath 1.0 has no bare boolean keyword syntax — the word `false` alone in an expression would be interpreted as an element name or QName, not as a boolean constant.
+
+Practical uses include: initialising boolean variables to a known `false` state, writing conditions that are intentionally disabled during development, and comparing the result of boolean expressions against a known `false` value.
+
+In most production stylesheets, `false()` appears less often than `true()` because conditions in `xsl:if` and predicates are already negated with `not()`, but it is occasionally needed in parameter defaults or variable declarations.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:boolean` — always returns `false`.
+
+## Examples
+
+### Disable a branch during development
+
+**Input XML:**
+```xml
+
+
+ Annual Report
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+ Debug output here
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Annual Report
+
+
+```
+
+### Compare the result of a boolean expression
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+ This feature is off.
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ This feature is off.
+
+
+
+```
+
+## Notes
+
+- XPath 1.0 has no bare boolean literals; `false()` and `true()` are the canonical way to represent boolean constants.
+- `$var = false()` is equivalent to `not($var)` when `$var` holds a boolean, but the intent can be clearer with the explicit comparison.
+- When outputting `false()` via `xsl:value-of`, the result is the string `"false"`, not the empty string.
+- In XSLT 2.0+ the function is unchanged; it remains a zero-argument function returning `xs:boolean`.
+
+## See also
+
+- [true()](../xpath-true)
+- [boolean()](../xpath-boolean)
+- [not()](../xpath-not)
diff --git a/site/content/xslt/functions/xpath-filter.md b/site/content/xslt/functions/xpath-filter.md
new file mode 100644
index 00000000..83507556
--- /dev/null
+++ b/site/content/xslt/functions/xpath-filter.md
@@ -0,0 +1,116 @@
+---
+title: "filter()"
+description: "Returns items from a sequence for which a predicate function returns true, discarding all others."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "filter(sequence, predicate)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`filter()` applies a predicate function to each item in a sequence and returns only those items for which the predicate returns `true`. It is the functional equivalent of an XPath predicate expression but accepts a function item, enabling reusable and composable filtering logic.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence to filter. |
+| `predicate` | function(item()) as xs:boolean | Yes | A function of arity 1 that returns true to keep the item, false to discard it. |
+
+## Return value
+
+`item()*` — the subsequence of items for which the predicate returned `true`, in document order.
+
+## Examples
+
+### Filtering even numbers
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 2
+ 4
+ 6
+ 8
+ 10
+
+```
+
+### Filtering XML nodes by attribute value
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+## Notes
+
+- The predicate function must return `xs:boolean`; effective boolean value (EBV) is not applied automatically.
+- `filter()` preserves the original sequence order.
+- Composable with `for-each()`, `fold-left()`, and `sort()` for pipeline-style data transformation.
+- For arrays, use `array:filter()` which operates on array members rather than a flat sequence.
+
+## See also
+
+- [for-each()](../xpath-for-each)
+- [fold-left()](../xpath-fold-left)
+- [fold-right()](../xpath-fold-right)
+- [for-each-pair()](../xpath-for-each-pair)
+- [array:filter()](../xpath-array-filter)
diff --git a/site/content/xslt/functions/xpath-floor.md b/site/content/xslt/functions/xpath-floor.md
new file mode 100644
index 00000000..91735dab
--- /dev/null
+++ b/site/content/xslt/functions/xpath-floor.md
@@ -0,0 +1,121 @@
+---
+title: "floor()"
+description: "Returns the largest integer not greater than the argument — equivalent to rounding a number down toward negative infinity."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "numeric function"
+syntax: "floor(number)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`floor()` returns the largest integer that is less than or equal to its argument. In plain terms, it rounds a number **down** toward negative infinity. For positive numbers this truncates the decimal part; for negative numbers this rounds away from zero.
+
+The argument is first converted to a number using the same rules as `number()`. If the argument is already an integer, it is returned unchanged. If the argument is `NaN` or infinite, the same special value is returned.
+
+Common uses include computing page numbers, calculating array indices from fractional results, and trimming calculated dimensions to integer pixel values.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `number` | xs:double | Yes | The number to round down. |
+
+## Return value
+
+`xs:double` — the largest integer value less than or equal to the argument.
+
+## Examples
+
+### Compute page count from item count
+
+**Input XML:**
+```xml
+
+
+ - A
+ - B
+ - C
+ - D
+ - E
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 5
+ 2
+
+```
+
+### Floor of positive and negative numbers
+
+**Input XML:**
+```xml
+
+
+ 3.7
+ -3.7
+ 5.0
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ -4
+ 5
+
+```
+
+## Notes
+
+- `floor(-3.7)` returns `-4`, not `-3`. Rounding is always toward negative infinity, not toward zero.
+- If the argument is `NaN`, `floor()` returns `NaN`.
+- If the argument is `Infinity` or `-Infinity`, the same infinity is returned unchanged.
+- `floor()` returns a `double` type in XPath 1.0, so the output may include a trailing `.0` on some processors when serialised. Use `round()` or integer arithmetic if you need a guaranteed integer format.
+- For rounding toward zero (truncation), there is no dedicated XPath 1.0 function; the common workaround is `floor($n)` for positive numbers or `ceiling($n)` for negative ones.
+
+## See also
+
+- [ceiling()](../xpath-ceiling)
+- [round()](../xpath-round)
+- [number()](../xpath-number)
diff --git a/site/content/xslt/functions/xpath-fold-left.md b/site/content/xslt/functions/xpath-fold-left.md
new file mode 100644
index 00000000..e7271717
--- /dev/null
+++ b/site/content/xslt/functions/xpath-fold-left.md
@@ -0,0 +1,114 @@
+---
+title: "fold-left()"
+description: "Accumulates a result by applying a function left-to-right over a sequence, starting from an initial zero value."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "fold-left(sequence, zero, function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`fold-left()` (also called a left reduce) processes a sequence from left to right. It begins with an initial accumulator value (`zero`) and repeatedly applies a binary function that takes the current accumulator and the next item, producing the new accumulator. The final accumulator value is the result.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence to fold over. |
+| `zero` | item()* | Yes | The initial accumulator value. |
+| `function` | function(item()*, item()) as item()* | Yes | A binary function: (accumulator, currentItem) → newAccumulator. |
+
+## Return value
+
+`item()*` — the final accumulated value after processing all items.
+
+## Examples
+
+### Summing a sequence of numbers
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 15
+ 120
+
+```
+
+### Building a string from a sequence
+
+**Input XML:**
+```xml
+
+
+ xslt
+ xpath
+ xml
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+xslt, xpath, xml
+```
+
+## Notes
+
+- `fold-left()` processes items in sequence order (left to right). For right-to-left, use `fold-right()`.
+- If the sequence is empty, the `zero` value is returned unchanged.
+- The accumulator can be any XDM value, including maps, arrays, or sequences.
+- For array-based folding, use `array:fold-left()`.
+
+## See also
+
+- [fold-right()](../xpath-fold-right)
+- [for-each()](../xpath-for-each)
+- [filter()](../xpath-filter)
+- [for-each-pair()](../xpath-for-each-pair)
+- [array:fold-left()](../xpath-array-fold-left)
diff --git a/site/content/xslt/functions/xpath-fold-right.md b/site/content/xslt/functions/xpath-fold-right.md
new file mode 100644
index 00000000..29788d89
--- /dev/null
+++ b/site/content/xslt/functions/xpath-fold-right.md
@@ -0,0 +1,105 @@
+---
+title: "fold-right()"
+description: "Accumulates a result by applying a function right-to-left over a sequence, starting from an initial zero value."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "fold-right(sequence, zero, function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`fold-right()` (also called a right reduce) processes a sequence from right to left. It begins with an initial accumulator value (`zero`) and repeatedly applies a binary function that combines the current item with the accumulated result. This produces different results from `fold-left()` for non-associative operations.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence to fold over. |
+| `zero` | item()* | Yes | The initial accumulator value (rightmost identity). |
+| `function` | function(item(), item()*) as item()* | Yes | A binary function: (currentItem, accumulator) → newAccumulator. |
+
+## Return value
+
+`item()*` — the final accumulated value after processing all items from right to left.
+
+## Examples
+
+### Right-fold to build a nested structure
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+cons(1, cons(2, cons(3, nil)))
+```
+
+### Reversing a sequence with fold-right
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - d
+ - c
+ - b
+ - a
+
+```
+
+## Notes
+
+- The function signature for `fold-right()` is `f(item, accumulator)` — note the argument order is reversed compared to `fold-left()`.
+- For commutative operations (sum, product), `fold-left()` and `fold-right()` produce identical results.
+- If the sequence is empty, the `zero` value is returned unchanged.
+- For array-based right folding, use `array:fold-right()`.
+
+## See also
+
+- [fold-left()](../xpath-fold-left)
+- [for-each()](../xpath-for-each)
+- [filter()](../xpath-filter)
+- [for-each-pair()](../xpath-for-each-pair)
+- [array:fold-right()](../xpath-array-fold-right)
diff --git a/site/content/xslt/functions/xpath-for-each-pair.md b/site/content/xslt/functions/xpath-for-each-pair.md
new file mode 100644
index 00000000..0435d3eb
--- /dev/null
+++ b/site/content/xslt/functions/xpath-for-each-pair.md
@@ -0,0 +1,117 @@
+---
+title: "for-each-pair()"
+description: "Applies a binary function to corresponding items from two sequences, returning the concatenated results."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "for-each-pair(seq1, seq2, function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`for-each-pair()` simultaneously iterates over two sequences, applying a binary function to each pair of corresponding items (first item from seq1 with first from seq2, second with second, etc.). Processing stops when the shorter sequence is exhausted.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `seq1` | item()* | Yes | The first sequence. |
+| `seq2` | item()* | Yes | The second sequence. |
+| `function` | function(item(), item()) as item()* | Yes | A binary function applied to each item pair. |
+
+## Return value
+
+`item()*` — concatenated results of applying the function to each pair; length equals `min(count(seq1), count(seq2))`.
+
+## Examples
+
+### Zipping two sequences into key-value pairs
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice
+ 30
+ Paris
+
+```
+
+### Computing pairwise differences
+
+**Input XML:**
+```xml
+
+
+ 10 20 35 50
+ 12 18 35 48
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ -2
+ 2
+ 0
+ 2
+
+```
+
+## Notes
+
+- When sequences have different lengths, the result length equals the shorter sequence — excess items from the longer sequence are ignored.
+- The function must accept exactly two arguments.
+- For array-based pair processing, use `array:for-each-pair()`.
+
+## See also
+
+- [for-each()](../xpath-for-each)
+- [filter()](../xpath-filter)
+- [fold-left()](../xpath-fold-left)
+- [fold-right()](../xpath-fold-right)
+- [array:for-each-pair()](../xpath-array-for-each-pair)
diff --git a/site/content/xslt/functions/xpath-for-each.md b/site/content/xslt/functions/xpath-for-each.md
new file mode 100644
index 00000000..28dca6c1
--- /dev/null
+++ b/site/content/xslt/functions/xpath-for-each.md
@@ -0,0 +1,114 @@
+---
+title: "for-each()"
+description: "Applies a function to each item of a sequence and returns the concatenation of all results."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "for-each(sequence, function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`for-each()` iterates over a sequence and applies a unary function to each item, returning a new sequence that is the concatenation of all individual results. It is the functional equivalent of `xsl:for-each` but operates as an XPath expression, making it composable with other higher-order functions.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence of items to iterate over. |
+| `function` | function(item()) as item()* | Yes | A function of arity 1 applied to each item. |
+
+## Return value
+
+`item()*` — the concatenated results of applying the function to each item.
+
+## Examples
+
+### Converting a sequence of strings to upper case
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ APPLE
+ BANANA
+ CHERRY
+
+```
+
+### Extracting attributes from nodes using for-each()
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 41.49
+ 25.50
+
+```
+
+## Notes
+
+- `for-each()` is an XPath function and must not be confused with the `xsl:for-each` instruction.
+- The function must accept exactly one argument.
+- Results from each invocation are concatenated into a flat sequence; use `array:for-each()` if you need to preserve array structure.
+- Composable with `filter()`, `fold-left()`, and `sort()` for pipeline-style processing.
+
+## See also
+
+- [filter()](../xpath-filter)
+- [fold-left()](../xpath-fold-left)
+- [fold-right()](../xpath-fold-right)
+- [for-each-pair()](../xpath-for-each-pair)
+- [array:for-each()](../xpath-array-for-each)
diff --git a/site/content/xslt/functions/xpath-format-date-time.md b/site/content/xslt/functions/xpath-format-date-time.md
new file mode 100644
index 00000000..4acb7557
--- /dev/null
+++ b/site/content/xslt/functions/xpath-format-date-time.md
@@ -0,0 +1,122 @@
+---
+title: "format-dateTime()"
+description: "Formats an xs:dateTime value into a human-readable string using a picture pattern, with optional locale and calendar support."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "format-dateTime(dateTime, picture, language?, calendar?, place?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`format-dateTime()` converts an `xs:dateTime` value into a formatted string using the picture pattern syntax shared by `format-date()` and `format-time()`. It supports all date and time component specifiers in a single call.
+
+Common specifiers:
+
+| Specifier | Meaning |
+|-----------|---------|
+| `[Y]` | Year (4 digits by default) |
+| `[M]` | Month as a number |
+| `[MNn]` | Month name (e.g., "April") |
+| `[D]` | Day of the month |
+| `[H]` | Hour, 24-hour clock (0–23) |
+| `[h]` | Hour, 12-hour clock (1–12) |
+| `[m]` | Minute |
+| `[s]` | Second |
+| `[P]` | AM/PM marker |
+| `[Z]` | Timezone offset |
+
+Width modifiers (e.g., `[D01]`, `[m01]`) control zero-padding.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `dateTime` | xs:dateTime? | Yes | The dateTime value to format. Returns an empty string for the empty sequence. |
+| `picture` | xs:string | Yes | The picture pattern controlling the output format. |
+| `language` | xs:string? | No | BCP 47 language tag (e.g., `"en"`, `"fr"`). |
+| `calendar` | xs:string? | No | Calendar system identifier. Implementation-defined. |
+| `place` | xs:string? | No | Place or timezone identifier. Implementation-defined. |
+
+## Return value
+
+`xs:string` — the formatted date-time string, or an empty string if `dateTime` is the empty sequence.
+
+## Examples
+
+### Format an event timestamp
+
+**Input XML:**
+```xml
+
+
+ Morning session
+ Afternoon workshop
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Morning session
+ Afternoon workshop
+
+```
+
+### Embed a generation timestamp in a report
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```xml
+
+ ...
+
+```
+
+## Notes
+
+- The input must be `xs:dateTime`, not a plain string. Cast attribute values with `xs:dateTime(@attr)`.
+- Picture syntax follows the XPath 2.0 specification, not Java or POSIX conventions.
+- To format only the date or time portion of a `xs:dateTime`, cast first: `format-date(xs:date(current-dateTime()), ...)`.
+
+## See also
+
+- [format-date()](../xpath-format-date)
+- [format-time()](../xpath-format-time)
+- [current-dateTime()](../xpath-current-date-time)
diff --git a/site/content/xslt/functions/xpath-format-number.md b/site/content/xslt/functions/xpath-format-number.md
new file mode 100644
index 00000000..175f0332
--- /dev/null
+++ b/site/content/xslt/functions/xpath-format-number.md
@@ -0,0 +1,129 @@
+---
+title: "format-number()"
+description: "Formats a number as a string using a picture pattern and an optional named decimal format, following the same rules as Java's DecimalFormat."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "numeric function"
+syntax: "format-number(number, pattern, decimal-format-name?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`format-number()` converts a number to a formatted string using a picture pattern string and optional named `xsl:decimal-format` settings. The pattern language follows the same conventions as Java's `java.text.DecimalFormat` class.
+
+The pattern is composed of two optional sub-patterns separated by a semicolon: the **positive pattern** and the **negative pattern**. If only one sub-pattern is given it applies to both positive and negative numbers (with a minus sign prepended for negatives).
+
+Common pattern characters:
+- `0` — mandatory digit position (outputs a zero if no digit is present).
+- `#` — optional digit position (omitted if not significant).
+- `.` — decimal separator.
+- `,` — grouping separator (thousands separator).
+- `%` — multiplies by 100 and appends a percent sign.
+- `E` — separates mantissa and exponent in scientific notation.
+
+The optional third argument names an `xsl:decimal-format` element that can customise the separator characters, infinity string, NaN string, and other locale-specific settings.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `number` | xs:double | Yes | The number to format. |
+| `pattern` | xs:string | Yes | The picture pattern string. |
+| `decimal-format-name` | xs:QName | No | Name of an `xsl:decimal-format` to use for locale-specific symbols. |
+
+## Return value
+
+`xs:string` — the formatted number as a string.
+
+## Examples
+
+### Format currency and percentages
+
+**Input XML:**
+```xml
+
+
+ 125678.9
+ 0.0735
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ $125,678.90
+ 7.35%
+
+```
+
+### Use a named decimal format for European locale
+
+**Input XML:**
+```xml
+
+
+ 1234.56
+ 0.5
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 1.234,56
+ 0,50
+
+```
+
+## Notes
+
+- `format-number(NaN, '0')` returns the NaN string defined by the `xsl:decimal-format` (default is `"NaN"`).
+- `format-number(number('abc'), '#')` also returns `"NaN"` because `number('abc')` is `NaN`.
+- The `%` pattern character multiplies by 100 before formatting; `‰` (per-mille) multiplies by 1000.
+- Negative numbers use the negative sub-pattern if provided; otherwise they use the positive pattern with a leading minus sign (using the minus sign character of the decimal format).
+- In XSLT 2.0+, `format-number()` is still available but the pattern language is enhanced and the function integrates with `xsl:decimal-format` improvements.
+
+## See also
+
+- [number()](../xpath-number)
+- [round()](../xpath-round)
+- [xsl:decimal-format](../xsl-decimal-format)
diff --git a/site/content/xslt/functions/xpath-format-time.md b/site/content/xslt/functions/xpath-format-time.md
new file mode 100644
index 00000000..ecf2611d
--- /dev/null
+++ b/site/content/xslt/functions/xpath-format-time.md
@@ -0,0 +1,114 @@
+---
+title: "format-time()"
+description: "Formats an xs:time value into a human-readable string using a picture pattern, with optional locale and calendar support."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "format-time(time, picture, language?, calendar?, place?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`format-time()` converts an `xs:time` value into a formatted string using the same **picture pattern** syntax used by `format-date()` and `format-dateTime()`. Picture components are enclosed in square brackets.
+
+Common time specifiers:
+
+| Specifier | Meaning |
+|-----------|---------|
+| `[H]` | Hour, 24-hour clock (0–23) |
+| `[h]` | Hour, 12-hour clock (1–12) |
+| `[m]` | Minute (0–59) |
+| `[s]` | Second (0–59) |
+| `[f]` | Fractional seconds |
+| `[P]` | AM/PM marker |
+
+Width modifiers like `[H01]` add zero-padding (e.g., `07` instead of `7`).
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `time` | xs:time? | Yes | The time value to format. Returns an empty string for the empty sequence. |
+| `picture` | xs:string | Yes | The picture pattern controlling the output format. |
+| `language` | xs:string? | No | BCP 47 language tag (e.g., `"en"`, `"fr"`). |
+| `calendar` | xs:string? | No | Calendar system identifier. Implementation-defined. |
+| `place` | xs:string? | No | Place or timezone identifier. Implementation-defined. |
+
+## Return value
+
+`xs:string` — the formatted time string, or an empty string if `time` is the empty sequence.
+
+## Examples
+
+### Format appointment times
+
+**Input XML:**
+```xml
+
+
+ Team standup
+ Client call
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Team standup
+ Client call
+
+```
+
+### Format the current time as HH:MM:SS
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```
+14:32:07
+```
+
+## Notes
+
+- The input must be an `xs:time` value, not a plain string. Cast with `xs:time(@attr)`.
+- Picture syntax is specific to XPath 2.0 and differs from Java `SimpleDateFormat` or POSIX `strftime`.
+- Language support for AM/PM markers and other named components varies by processor.
+
+## See also
+
+- [format-date()](../xpath-format-date)
+- [format-dateTime()](../xpath-format-date-time)
+- [current-time()](../xpath-current-time)
diff --git a/site/content/xslt/functions/xpath-function-arity.md b/site/content/xslt/functions/xpath-function-arity.md
new file mode 100644
index 00000000..426604e4
--- /dev/null
+++ b/site/content/xslt/functions/xpath-function-arity.md
@@ -0,0 +1,109 @@
+---
+title: "function-arity()"
+description: "Returns the number of arguments (arity) that a function item accepts."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "function-arity(function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`function-arity()` returns the arity — the number of parameters — of a function item. This is useful when working with higher-order functions to validate that a function accepts the expected number of arguments before calling it, or when building generic utilities that inspect function items.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `function` | function(*) | Yes | The function item whose arity is to be returned. |
+
+## Return value
+
+`xs:integer` — the number of parameters the function accepts.
+
+## Examples
+
+### Checking arity before apply()
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 1
+ HELLO
+
+```
+
+### Introspecting a list of functions
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ fn:upper-case 1
+ fn:substring 2
+ fn:substring 3
+ anonymous 2
+
+```
+
+## Notes
+
+- Partial function application (e.g., `substring(?, 1, 3)`) reduces the arity by the number of bound arguments.
+- `function-arity()` never returns the empty sequence; it always returns a non-negative integer.
+- A zero-arity function (`function() { ... }`) returns `0`.
+
+## See also
+
+- [function-name()](../xpath-function-name)
+- [function-lookup()](../xpath-function-lookup)
+- [apply()](../xpath-apply)
diff --git a/site/content/xslt/functions/xpath-function-available.md b/site/content/xslt/functions/xpath-function-available.md
new file mode 100644
index 00000000..1c48248b
--- /dev/null
+++ b/site/content/xslt/functions/xpath-function-available.md
@@ -0,0 +1,123 @@
+---
+title: "function-available()"
+description: "Returns true if the named function is available in the current XSLT processor, supporting portable use of extension functions."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "function-available(name)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`function-available()` tests whether the named function can be called in the current transformation context and returns a boolean. This includes core XPath functions, XSLT-specific functions (such as `document()`, `key()`, and `format-number()`), and any extension functions provided by the processor or bound via namespace declarations.
+
+The argument is a string containing the QName of the function. If the QName is in no namespace or the `fn:` namespace, built-in XPath/XSLT functions are tested. If it is in another namespace, vendor or EXSLT extension functions are tested.
+
+`function-available()` allows stylesheets to be written once and run on multiple processors, branching between native and extension implementations as needed. It is commonly paired with `element-available()` for comprehensive capability detection.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:string | Yes | A QName string naming the function to test. |
+
+## Return value
+
+`xs:boolean` — `true` if the function is available and callable, `false` otherwise.
+
+## Examples
+
+### Test for core and extension functions
+
+**Input XML:**
+```xml
+
+3.14
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (Saxon with EXSLT):**
+```xml
+
+ true
+ true
+ false
+
+```
+
+### Conditional use of an EXSLT function
+
+**Input XML:**
+```xml
+
+
+ - 3
+ - 1
+ - 2
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+ exsl:node-set available
+
+
+ Fallback: no node-set conversion
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `function-available()` tests callable functions only — it does not test XSLT instruction elements. Use `element-available()` for that.
+- The prefix in the QName string must be declared in the stylesheet for namespace-qualified function names; otherwise an error is raised.
+- All standard XPath 1.0 core functions (`string()`, `number()`, `concat()`, etc.) always return `true` in a conformant processor.
+- In XSLT 2.0+, `function-available()` remains available. It can optionally take a second argument specifying the arity (number of arguments) of the function to test.
+
+## See also
+
+- [element-available()](../xpath-element-available)
+- [system-property()](../xpath-system-property)
diff --git a/site/content/xslt/functions/xpath-function-lookup.md b/site/content/xslt/functions/xpath-function-lookup.md
new file mode 100644
index 00000000..045138fe
--- /dev/null
+++ b/site/content/xslt/functions/xpath-function-lookup.md
@@ -0,0 +1,114 @@
+---
+title: "function-lookup()"
+description: "Returns a function item identified by its QName and arity, or the empty sequence if no such function is available."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "function-lookup(name, arity)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`function-lookup()` looks up a function by its expanded QName and arity (number of parameters) in the static context. If found, it returns the function as a function item; if no such function exists, it returns the empty sequence. This enables optional feature detection and dynamic dispatch patterns.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:QName | Yes | The expanded QName of the function to look up. |
+| `arity` | xs:integer | Yes | The number of arguments (arity) the function accepts. |
+
+## Return value
+
+`function(*)?` — the matching function item, or the empty sequence if not found.
+
+## Examples
+
+### Safe lookup before calling
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ math:sqrt not available
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 4
+
+```
+
+### Building a function dispatch table
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - HELLO WORLD
+ - hello world
+ - Hello World
+
+```
+
+## Notes
+
+- The `name` argument must be an `xs:QName` created with `xs:QName()` or a namespace-aware constructor.
+- For built-in XPath functions, the namespace URI is `http://www.w3.org/2005/xpath-functions`.
+- Returns the empty sequence (not an error) when the function is not found, making it safe for feature detection.
+- User-defined functions declared with `xsl:function` are also accessible via `function-lookup()`.
+
+## See also
+
+- [apply()](../xpath-apply)
+- [function-name()](../xpath-function-name)
+- [function-arity()](../xpath-function-arity)
+- [for-each()](../xpath-for-each)
diff --git a/site/content/xslt/functions/xpath-function-name.md b/site/content/xslt/functions/xpath-function-name.md
new file mode 100644
index 00000000..78b7ca9a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-function-name.md
@@ -0,0 +1,115 @@
+---
+title: "function-name()"
+description: "Returns the QName of a named function item, or the empty sequence if the function is anonymous."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "function-name(function)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`function-name()` inspects a function item and returns its QName if the function has a name. For anonymous inline functions (created with `function(...)` expressions), it returns the empty sequence. This is useful for logging, debugging, and dynamic function inspection.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `function` | function(*) | Yes | The function item to inspect. |
+
+## Return value
+
+`xs:QName?` — the QName of the function, or the empty sequence for anonymous functions.
+
+## Examples
+
+### Inspecting named and anonymous functions
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ f:double
+ anonymous
+ fn:upper-case
+
+```
+
+### Logging function calls in a dispatch table
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ fn:upper-case 1
+ fn:lower-case 1
+ fn:normalize-space 1
+
+```
+
+## Notes
+
+- Anonymous functions created with inline `function(...)` syntax return the empty sequence.
+- For built-in functions, the local name is the function name without the `fn:` prefix, but `function-name()` returns the fully expanded QName.
+- Use `local-name-from-QName()` and `namespace-uri-from-QName()` to decompose the returned QName.
+
+## See also
+
+- [function-arity()](../xpath-function-arity)
+- [function-lookup()](../xpath-function-lookup)
+- [apply()](../xpath-apply)
diff --git a/site/content/xslt/functions/xpath-generate-id.md b/site/content/xslt/functions/xpath-generate-id.md
new file mode 100644
index 00000000..ead8a846
--- /dev/null
+++ b/site/content/xslt/functions/xpath-generate-id.md
@@ -0,0 +1,136 @@
+---
+title: "generate-id()"
+description: "Returns a unique string identifier for a node, guaranteed to be a valid XML name and stable within a single transformation run."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "generate-id(node?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`generate-id()` returns a string that uniquely identifies a node within the current transformation. The string is guaranteed to:
+
+- Be a valid XML `Name` (it can be used as an attribute value or part of an ID).
+- Be unique: different nodes in the same transformation produce different IDs.
+- Be consistent: calling `generate-id()` on the same node multiple times within one transformation always returns the same string.
+
+The generated value is arbitrary and processor-specific. It may change between runs or between different XSLT processors; do not store it in output that must be reproducible.
+
+When called with no argument, `generate-id()` uses the context node. If the argument is an empty node-set, the empty string `""` is returned.
+
+Common uses include generating `id`/`href` pairs for internal cross-references in HTML output, implementing the Muenchian grouping technique, and creating unique element names when converting to formats that require them.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node-set | No | The node to identify. Defaults to the context node. If empty, returns `""`. |
+
+## Return value
+
+`xs:string` — a unique, valid XML Name for the node, or `""` for an empty node-set.
+
+## Examples
+
+### Generate anchor links in HTML output
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (IDs are processor-generated):**
+```html
+
+
+ Introduction
+ Welcome.
+ Usage
+ How to use it.
+
+```
+
+### Muenchian grouping — test node identity
+
+**Input XML:**
+```xml
+
+
+ - One
+ - Two
+ - Three
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+ items
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 2 items
+ 1 items
+
+```
+
+## Notes
+
+- The generated ID is **not persistent**: it may differ between processors and between runs of the same processor. Do not use it as a stable key in output databases or cross-document references.
+- `generate-id()` on an empty node-set returns `""`, not an error. Check for this case if the argument might be empty.
+- Two calls to `generate-id()` on the same node within one transformation always return the same value, which is the property that makes the Muenchian grouping technique work.
+- In XSLT 2.0+, `generate-id()` remains available and unchanged. The `xsl:for-each-group` instruction is usually a cleaner alternative for grouping tasks.
+
+## See also
+
+- [id()](../xpath-id)
+- [key()](../xpath-key)
diff --git a/site/content/xslt/functions/xpath-has-children.md b/site/content/xslt/functions/xpath-has-children.md
new file mode 100644
index 00000000..bb6563cc
--- /dev/null
+++ b/site/content/xslt/functions/xpath-has-children.md
@@ -0,0 +1,105 @@
+---
+title: "has-children()"
+description: "Returns true if the node has one or more child nodes; defaults to the context node if no argument is supplied."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "has-children(node?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`has-children()` tests whether a node has at least one child node. A child node may be an element, text node, comment, or processing instruction. Attribute nodes and namespace nodes are not children in the XPath data model, so their presence alone does not cause `has-children()` to return `true`.
+
+When called without arguments, the function tests the context node. When a node is supplied as an argument, that node is tested. If the argument is the empty sequence, `false` is returned.
+
+The function is particularly useful in streaming mode where examining all children of a node is expensive or impossible after the streaming pass. `has-children()` can be evaluated during streaming as a simple flag before the children are consumed.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node()? | No | The node to test. Defaults to the context node if omitted. |
+
+## Return value
+
+`xs:boolean` — `true` if the node has one or more child nodes, `false` otherwise.
+
+## Examples
+
+### Distinguishing leaf and branch elements
+
+**Input XML:**
+```xml
+
+
+
+ A
+ B
+
+ C
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+### Using has-children() with a supplied node
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+true
+false
+```
+
+## Notes
+
+- `has-children()` is equivalent to `exists(child::node())` but may be more efficient when the processor does not need to materialize the child sequence.
+- In streaming mode (`xsl:stream`), `has-children()` is one of the few node tests that can be applied without consuming the children.
+- Attribute nodes never have children in the XPath data model, so `has-children(@attr)` always returns `false`.
+- Document nodes may also be tested; a document with at least one child element returns `true`.
+
+## See also
+
+- [innermost()](../xpath-innermost)
+- [outermost()](../xpath-outermost)
+- [path()](../xpath-path)
diff --git a/site/content/xslt/functions/xpath-hours-from-time.md b/site/content/xslt/functions/xpath-hours-from-time.md
new file mode 100644
index 00000000..62143cec
--- /dev/null
+++ b/site/content/xslt/functions/xpath-hours-from-time.md
@@ -0,0 +1,100 @@
+---
+title: "hours-from-time()"
+description: "Extracts the hours component from an xs:time value as an xs:integer in the range 0–23."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "hours-from-time(time)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`hours-from-time()` returns the hours component of an `xs:time` value as an `xs:integer` between 0 and 23. If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `time` | xs:time? | Yes | The time value from which to extract the hours. |
+
+## Return value
+
+`xs:integer?` — integer from 0 to 23, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Classify times as morning, afternoon, or evening
+
+**Input XML:**
+```xml
+
+
+ Team standup
+ Client call
+ Dinner meeting
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Team standup
+ Client call
+ Dinner meeting
+
+```
+
+### Extract hour from the current time
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```
+Current hour: 14
+```
+
+## Notes
+
+- The argument must be typed as `xs:time`. Cast string values with `xs:time(@attr)`.
+- Returns values in the 24-hour clock range (0–23).
+- For `xs:dateTime` values, use `hours-from-dateTime()`.
+
+## See also
+
+- [minutes-from-time()](../xpath-minutes-from-time)
+- [seconds-from-time()](../xpath-seconds-from-time)
+- [current-time()](../xpath-current-time)
diff --git a/site/content/xslt/functions/xpath-id.md b/site/content/xslt/functions/xpath-id.md
new file mode 100644
index 00000000..6becae84
--- /dev/null
+++ b/site/content/xslt/functions/xpath-id.md
@@ -0,0 +1,109 @@
+---
+title: "id()"
+description: "Selects elements in the document whose ID attribute value matches the given string or space-separated list of IDs."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "id(string)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`id()` returns a node-set of all elements in the same document as the context node whose **ID-typed attribute** matches one or more ID values provided in the argument.
+
+The argument may be:
+- A **string** containing one or more whitespace-separated ID values — each is looked up independently.
+- A **node-set** — each node is converted to its string value, that string is treated as a whitespace-separated list of IDs, and all matching elements are returned.
+
+An element participates in ID lookup only if the document has an associated DTD or schema that declares the attribute as type `ID`. Without such a declaration, `id()` will always return an empty node-set, even if an attribute is named `id`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string or node-set | Yes | One or more whitespace-separated ID values to look up. |
+
+## Return value
+
+`node-set` — the elements whose ID-typed attribute matches the given values, in document order, with no duplicates.
+
+## Examples
+
+### Look up a single element by ID (requires DTD)
+
+**Input XML:**
+```xml
+
+
+
+
+
+]>
+
+ Widget
+ Gadget
+ Doohickey
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+Gadget
+```
+
+### Look up multiple elements by a space-separated list
+
+**Input XML (with DTD as above):**
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Widget
+ - Doohickey
+
+```
+
+## Notes
+
+- `id()` only works when the XML document has a DTD that declares the attribute type as `ID`. Without a DTD validation pass, the processor has no way to know which attribute holds the ID.
+- In practice, many documents use an attribute named `id` or `xml:id` without a DTD. For those, use an XPath predicate such as `//*[@id = 'myId']` or the `key()` function instead.
+- `xml:id` (defined by the W3C xml:id specification) is automatically treated as an ID-typed attribute by conforming XSLT 2.0+ processors without requiring a DTD.
+- The result node-set is always in document order and contains no duplicates, even if the same ID appears more than once in the argument string.
+
+## See also
+
+- [key()](../xpath-key)
+- [generate-id()](../xpath-generate-id)
diff --git a/site/content/xslt/functions/xpath-implicit-timezone.md b/site/content/xslt/functions/xpath-implicit-timezone.md
new file mode 100644
index 00000000..20ee850d
--- /dev/null
+++ b/site/content/xslt/functions/xpath-implicit-timezone.md
@@ -0,0 +1,86 @@
+---
+title: "implicit-timezone()"
+description: "Returns the processor's implicit timezone as an xs:dayTimeDuration, used when date/time values have no explicit timezone."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "implicit-timezone()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`implicit-timezone()` returns the implicit timezone of the XPath evaluation context as an `xs:dayTimeDuration`. This is the timezone assumed when comparing or formatting date/time values that do not carry an explicit timezone component.
+
+The value is processor-defined but typically reflects the system's local timezone. It is expressed as a positive or negative duration relative to UTC (e.g., `PT1H` for UTC+1, `-PT5H` for UTC-5).
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:dayTimeDuration` — the implicit timezone offset from UTC. The value is always a whole number of minutes.
+
+## Examples
+
+### Display the implicit timezone
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example for UTC+1):**
+```xml
+
+ PT1H
+
+```
+
+### Normalize a timezone-free date to UTC
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `implicit-timezone()` is used internally by the processor when comparing date/time values that lack explicit timezone information.
+- To retrieve the current date/time with the implicit timezone already applied, use `current-date()`, `current-time()`, or `current-dateTime()`.
+- To convert values to a specific timezone, use the `adjust-date-to-timezone()`, `adjust-time-to-timezone()`, or `adjust-dateTime-to-timezone()` functions.
+- The implicit timezone can be set programmatically in Saxon via the `Configuration` API, but is typically the JVM's default timezone.
+
+## See also
+
+- [current-date()](../xpath-current-date)
+- [current-time()](../xpath-current-time)
+- [current-dateTime()](../xpath-current-date-time)
diff --git a/site/content/xslt/functions/xpath-index-of.md b/site/content/xslt/functions/xpath-index-of.md
new file mode 100644
index 00000000..38d2027a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-index-of.md
@@ -0,0 +1,116 @@
+---
+title: "index-of()"
+description: "Returns a sequence of 1-based integer positions where a value occurs in a sequence, using value equality."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "index-of(sequence, value, collation?)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`index-of()` searches a sequence for all occurrences of a given value and returns a sequence of the 1-based positions where matches are found. If the value does not appear in the sequence, the function returns an empty sequence.
+
+Value equality follows the same rules as the `=` operator: numeric equality for numbers, Unicode codepoint comparison for strings (unless a collation is specified), and so on. The function compares atomic values; if `sequence` contains nodes, their typed values are compared.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | xs:anyAtomicType* | Yes | The sequence to search. |
+| `value` | xs:anyAtomicType | Yes | The value to look for. |
+| `collation` | xs:string | No | A collation URI for string comparison. |
+
+## Return value
+
+`xs:integer*` — a sequence of 1-based positions where `value` equals the item in `sequence`. Returns an empty sequence if no match is found.
+
+## Examples
+
+### Finding where a value appears
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 2, 4, 6
+ 2
+ true
+
+```
+
+### Checking attribute value membership
+
+**Input XML:**
+```xml
+
+
+ pdf xml html txt
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+## Notes
+
+- Positions are 1-based, consistent with XPath conventions (as in `position()`, `substring()`, `subsequence()`).
+- For a simple membership test, the `=` operator with a sequence is often more readable: `$value = $sequence`.
+- `index-of()` returns all matching positions, not just the first. Use `[1]` to get only the first.
+- The function operates on atomic values. Nodes in the sequence are atomized before comparison.
+
+## See also
+
+- [distinct-values()](../xpath-distinct-values)
+- [subsequence()](../xpath-subsequence)
+- [remove()](../xpath-remove)
+- [insert-before()](../xpath-insert-before)
diff --git a/site/content/xslt/functions/xpath-innermost.md b/site/content/xslt/functions/xpath-innermost.md
new file mode 100644
index 00000000..1367d3ac
--- /dev/null
+++ b/site/content/xslt/functions/xpath-innermost.md
@@ -0,0 +1,110 @@
+---
+title: "innermost()"
+description: "Returns the nodes from the input that are not ancestors of any other node in the input sequence."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "innermost(nodes)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`innermost()` filters a sequence of nodes to keep only those that are not ancestors of any other node in the same sequence. In other words, it removes from the sequence any node that has a descendant also present in the sequence, retaining only the deepest nodes.
+
+The result is returned in document order. `innermost()` is the complement of `outermost()`: where `outermost()` keeps the highest ancestors, `innermost()` keeps the lowest descendants. Together they let you work with the boundaries of an overlapping selection.
+
+This function is especially useful when combining results from multiple XPath expressions that may select nodes at different levels of the same subtree.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `nodes` | node()* | Yes | The sequence of nodes to filter. |
+
+## Return value
+
+`node()*` — the subset of input nodes that have no descendants in the input sequence, in document order.
+
+## Examples
+
+### Filtering to leaf-level selections
+
+**Input XML:**
+```xml
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+### Comparing innermost and outermost
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+## Notes
+
+- If no node in the sequence is an ancestor of any other, `innermost()` returns the full sequence in document order.
+- If the sequence contains a single node, `innermost()` returns that same node.
+- `innermost()` eliminates redundancy when merging selections that may overlap at different levels of nesting.
+- The result is always in document order regardless of the input order.
+
+## See also
+
+- [outermost()](../xpath-outermost)
+- [has-children()](../xpath-has-children)
+- [path()](../xpath-path)
diff --git a/site/content/xslt/functions/xpath-insert-before.md b/site/content/xslt/functions/xpath-insert-before.md
new file mode 100644
index 00000000..e08768c7
--- /dev/null
+++ b/site/content/xslt/functions/xpath-insert-before.md
@@ -0,0 +1,115 @@
+---
+title: "insert-before()"
+description: "Returns a new sequence with one or more items inserted at a specified 1-based position, without modifying the original sequence."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "insert-before(sequence, position, insert)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`insert-before()` constructs a new sequence by inserting all items from `insert` immediately before the item at `position` in `sequence`. The original sequence is not modified — XPath sequences are immutable values.
+
+Position is 1-based. Special cases:
+
+- If `position` is less than 1, the inserted items are placed at the beginning.
+- If `position` is greater than the length of `sequence`, the inserted items are placed at the end.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The original sequence. |
+| `position` | xs:integer | Yes | The 1-based position before which insertion occurs. |
+| `insert` | item()* | Yes | The items to insert. May be a single item or a sequence. |
+
+## Return value
+
+`item()*` — a new sequence with the inserted items at the specified position.
+
+## Examples
+
+### Inserting a header item into a sequence
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ red
+ yellow
+ green
+ blue
+
+```
+
+### Building a sequence with a separator between items
+
+**Input XML:**
+```xml
+
+
+ Init
+ Process
+ Validate
+ Done
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+Init → Process Validate Done
+```
+
+## Notes
+
+- `insert-before()` is a functional operation — the original sequence is unchanged. Assign the result to a new variable.
+- `insert-before($seq, 1, $item)` is equivalent to prepending: result is `($item, $seq...)`.
+- `insert-before($seq, count($seq)+1, $item)` is equivalent to appending: result is `($seq..., $item)`.
+- The `insert` argument may itself be a sequence, allowing multiple items to be inserted at once.
+
+## See also
+
+- [remove()](../xpath-remove)
+- [subsequence()](../xpath-subsequence)
+- [reverse()](../xpath-reverse)
+- [index-of()](../xpath-index-of)
diff --git a/site/content/xslt/functions/xpath-json-doc.md b/site/content/xslt/functions/xpath-json-doc.md
new file mode 100644
index 00000000..7950a7f7
--- /dev/null
+++ b/site/content/xslt/functions/xpath-json-doc.md
@@ -0,0 +1,112 @@
+---
+title: "json-doc()"
+description: "Retrieves a JSON document from a URI and parses it into XDM value using the same rules as parse-json()."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "JSON function"
+syntax: "json-doc(uri, options?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`json-doc()` loads a JSON document from a URI and returns it as an XDM value using the same mapping rules as `parse-json()`. JSON objects become XDM maps, JSON arrays become XDM arrays, and scalar JSON values become corresponding XDM atomic types. The function is the JSON counterpart to `doc()` for XML documents.
+
+The `options` map accepts the same keys as `parse-json()`. The URI is resolved against the base URI of the stylesheet. If the URI cannot be dereferenced or the content is not valid JSON, a dynamic error is raised.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `uri` | xs:string? | Yes | The URI of the JSON resource to load. Returns empty sequence if the URI is the empty sequence. |
+| `options` | map(xs:string, item())? | No | Parsing options, same as for parse-json(). |
+
+## Return value
+
+`item()?` — the parsed JSON content as an XDM map, array, or atomic value.
+
+## Examples
+
+### Loading a JSON configuration file
+
+**JSON file (config.json):**
+```json
+{
+ "host": "db.example.com",
+ "port": 5432,
+ "database": "production"
+}
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ db.example.com
+ 5432
+ production
+
+```
+
+### Loading a JSON array from a URL
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+## Notes
+
+- `json-doc()` caches results in the same way as `doc()`; multiple calls with the same URI within a transformation return the same XDM value.
+- Unlike `doc()`, the result is not a node tree but an XDM atomic or composite value, so you cannot navigate it with XPath axis steps.
+- The function is not available in XSLT 2.0; use `parse-json(unparsed-text(uri))` as a workaround in 2.0 processors that support `unparsed-text()`.
+- Relative URIs are resolved against the static base URI of the calling expression.
+
+## See also
+
+- [parse-json()](../xpath-parse-json)
+- [json-to-xml()](../xpath-json-to-xml)
+- [xml-to-json()](../xpath-xml-to-json)
diff --git a/site/content/xslt/functions/xpath-json-to-xml.md b/site/content/xslt/functions/xpath-json-to-xml.md
new file mode 100644
index 00000000..093b9d2b
--- /dev/null
+++ b/site/content/xslt/functions/xpath-json-to-xml.md
@@ -0,0 +1,128 @@
+---
+title: "json-to-xml()"
+description: "Converts a JSON string to its W3C standard XML representation, producing an element tree navigable with XPath."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "JSON function"
+syntax: "json-to-xml(string, options?)"
+tags: ["xslt", "reference", "xslt3", "xpath"]
+---
+
+## Description
+
+`json-to-xml()` parses a JSON string and converts it into an XML element tree following the W3C XSLT 3.0 specification for the JSON-to-XML mapping. Every JSON construct is represented as an element in the `http://www.w3.org/2005/xpath-functions` namespace: objects become `` elements, arrays become `` elements, strings become ``, numbers become ``, booleans become ``, and null becomes ``. Object keys are stored in a `key` attribute.
+
+The result is a proper XML node tree, so it can be queried with standard XPath axis steps, processed with `xsl:apply-templates`, or further transformed. To go the other way (XML back to JSON text), use `xml-to-json()`. To obtain an XDM map/array instead of an XML tree, use `parse-json()`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | `xs:string?` | Yes | The JSON string to convert. Returns empty sequence if empty. |
+| `options` | `map(xs:string, item()*)` | No | A map of options; `"liberal"` (boolean) relaxes strict JSON parsing. |
+
+## Return value
+
+`document-node()?` — a document node whose root element is a ``, ``, or scalar element in the `http://www.w3.org/2005/xpath-functions` namespace, or empty sequence if the input is empty.
+
+## Examples
+
+### Converting a JSON object to XML and reading properties
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice
+ 30
+ true
+
+```
+
+### Converting a JSON array and applying templates to each member
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Assuming `cities.json` contains `[{"city":"Paris","pop":2161000},{"city":"Lyon","pop":516092}]`:
+
+**Output:**
+```xml
+
+
+ 2161000
+
+
+ 516092
+
+
+```
+
+## Notes
+
+- The namespace URI for generated elements is `http://www.w3.org/2005/xpath-functions`. Bind it to a prefix (commonly `fn`) in your stylesheet to use axis steps efficiently.
+- Object keys that are not valid XML `NCName` values are still stored verbatim in the `key` attribute; use `@key = 'the-key'` to match them.
+- For deeply nested or large JSON structures, `xsl:apply-templates` with mode-based pattern matching is more maintainable than long `//` descendant paths.
+- If you only need value access by key and not full axis navigation, `parse-json()` returning XDM maps and arrays is simpler.
+
+## See also
+
+- [xml-to-json()](../xpath-xml-to-json)
+- [parse-json()](../xpath-parse-json)
+- [json-doc()](../xpath-json-doc)
diff --git a/site/content/xslt/functions/xpath-lang.md b/site/content/xslt/functions/xpath-lang.md
new file mode 100644
index 00000000..895516b6
--- /dev/null
+++ b/site/content/xslt/functions/xpath-lang.md
@@ -0,0 +1,116 @@
+---
+title: "lang()"
+description: "Returns true if the context node's xml:lang attribute matches the given language code, following BCP 47 prefix rules."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "lang(string)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`lang()` tests whether the context node is written in the language identified by the argument string. It walks up the ancestor-or-self axis to find the nearest `xml:lang` attribute and then compares its value to the argument using a case-insensitive prefix match.
+
+The matching rule is: if the `xml:lang` value equals the argument (case-insensitive), or if it equals the argument followed by a hyphen (`-`) and any subtag, then `lang()` returns `true`. For example, `lang('en')` returns `true` for nodes where `xml:lang` is `en`, `en-US`, `en-GB`, or `EN-AU`.
+
+This makes `lang()` well-suited for filtering multilingual documents by language family without needing to enumerate every regional variant explicitly.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string | Yes | The language code to test against (e.g. `"en"`, `"fr"`, `"zh-Hant"`). |
+
+## Return value
+
+`xs:boolean` — `true` if the context node's effective `xml:lang` matches the argument, `false` otherwise.
+
+## Examples
+
+### Filter paragraphs by language
+
+**Input XML:**
+```xml
+
+
+ Hello, world.
+ Bonjour le monde.
+ Cheers, mate.
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Hello, world.
+ Cheers, mate.
+
+```
+
+### Inherited xml:lang from ancestor
+
+**Input XML:**
+```xml
+
+
+
+ Einleitung
+ Ein einleitender Absatz.
+ An English aside.
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Ein einleitender Absatz.
+
+```
+
+## Notes
+
+- The comparison is **case-insensitive**: `lang('EN')` and `lang('en')` behave identically.
+- `lang()` searches the **nearest ancestor-or-self** that carries an `xml:lang` attribute. If no such ancestor exists, the function returns `false`.
+- The argument is matched as a **prefix**: `lang('zh')` matches `zh-Hant` and `zh-Hans` but not `zho`.
+- `lang()` only recognises the `xml:lang` attribute in the XML namespace. A plain `lang` attribute without the `xml:` prefix is ignored.
+- In XSLT 2.0+, `lang()` is still available with the same semantics; additionally, the `xsl:sort` element's `lang` attribute drives language-sensitive collation separately.
+
+## See also
+
+- [normalize-space()](../xpath-normalize-space)
+- [string()](../xpath-string)
diff --git a/site/content/xslt/functions/xpath-local-name-from-qname.md b/site/content/xslt/functions/xpath-local-name-from-qname.md
new file mode 100644
index 00000000..93bbe46e
--- /dev/null
+++ b/site/content/xslt/functions/xpath-local-name-from-qname.md
@@ -0,0 +1,102 @@
+---
+title: "local-name-from-QName()"
+description: "Returns the local part of an xs:QName value as an xs:NCName."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "QName function"
+syntax: "local-name-from-QName(qname)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`local-name-from-QName()` extracts the local part of an `xs:QName` value. The local name is the part after the colon in a prefixed name, or the entire name when no prefix is present. The result is an `xs:NCName` (a non-colonized name), which is a subtype of `xs:string`.
+
+This function works with `xs:QName` values — typed values produced by `QName()`, `resolve-QName()`, or schema-validated content — not raw string representations of names. If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `qname` | xs:QName? | Yes | The QName from which to extract the local name. |
+
+## Return value
+
+`xs:NCName?` — the local part of the QName, or the empty sequence if the argument is empty.
+
+## Examples
+
+### Extracting local names from constructed QNames
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ product
+ simple
+
+```
+
+### Using with node-name()
+
+**Input XML:**
+```xml
+
+
+ text
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+```
+
+## Notes
+
+- `local-name-from-QName()` operates on typed `xs:QName` values, not on string representations. To get the local name of a node, use `local-name()` instead.
+- The result is identical to `local-name()` on a node whose expanded name matches the QName.
+- When working with dynamically constructed QNames, this function is the companion to `namespace-uri-from-QName()` and `prefix-from-QName()`.
+
+## See also
+
+- [namespace-uri-from-QName()](../xpath-namespace-uri-from-qname)
+- [prefix-from-QName()](../xpath-prefix-from-qname)
+- [resolve-QName()](../xpath-resolve-qname)
+- [QName()](../xpath-qname)
diff --git a/site/content/xslt/functions/xpath-local-name.md b/site/content/xslt/functions/xpath-local-name.md
new file mode 100644
index 00000000..986a1064
--- /dev/null
+++ b/site/content/xslt/functions/xpath-local-name.md
@@ -0,0 +1,121 @@
+---
+title: "local-name()"
+description: "Returns the local part of the expanded name of a node, stripping any namespace prefix."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "local-name(node?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`local-name()` returns the local part of a node's name — that is, the part of the qualified name after the colon, or the full name if no prefix is present. For example, a node named `xhtml:div` has a local name of `div`.
+
+When called without an argument, it returns the local name of the context node. When called with a node-set argument, it returns the local name of the first node in the node-set in document order. For nodes without an expanded name (such as text nodes, comments, and processing instructions with no target), the function returns the empty string `""`.
+
+`local-name()` is useful when writing stylesheets that must process elements regardless of the namespace prefix used, or when generating output where you want to replicate element names without their prefix.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node-set | No | The node whose local name to return. Defaults to the context node. |
+
+## Return value
+
+`xs:string` — the local part of the node's name, or `""` for nodes with no name.
+
+## Examples
+
+### Print the local name of each element
+
+**Input XML:**
+```xml
+
+
+ Main Title
+ Body content
+ Plain element
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+### Generic copy stripping namespace prefixes
+
+**Input XML:**
+```xml
+
+
+
+ Value
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Value
+
+
+```
+
+## Notes
+
+- For element and attribute nodes, `local-name()` returns the NCName portion after the colon. For unprefixed elements, the local name equals the qualified name.
+- For text nodes, comment nodes, and document nodes, `local-name()` returns `""`.
+- Processing instruction nodes return the PI target as their local name.
+- `local-name()` and `name()` return the same value for nodes with no namespace prefix.
+- In XSLT 2.0+, `fn:local-name()` is unchanged but also accepts a single node as argument (not a node-set); passing more than one node is an error.
+
+## See also
+
+- [name()](../xpath-name)
+- [namespace-uri()](../xpath-namespace-uri)
diff --git a/site/content/xslt/functions/xpath-lower-case.md b/site/content/xslt/functions/xpath-lower-case.md
new file mode 100644
index 00000000..db7ff472
--- /dev/null
+++ b/site/content/xslt/functions/xpath-lower-case.md
@@ -0,0 +1,117 @@
+---
+title: "lower-case()"
+description: "Converts every character of a string to its Unicode lowercase equivalent using locale-independent Unicode case mapping."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "lower-case(string)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`lower-case()` returns a copy of the input string with every character converted to lowercase according to Unicode default case mappings. The conversion is locale-independent. If the argument is an empty sequence, the function returns the empty string `""`.
+
+It is the complement of `upper-case()` and is frequently used for normalization before comparison, sorting, or searching — ensuring that strings like `"XML"`, `"xml"`, and `"Xml"` are treated identically.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | The string to convert. |
+
+## Return value
+
+`xs:string` — the input string with all characters mapped to lowercase.
+
+## Examples
+
+### Normalizing element text for comparison
+
+**Input XML:**
+```xml
+
+
+ XSLT
+ XPath
+ xml
+ JSON
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ xslt
+ xpath
+ xml
+ json
+
+```
+
+### Generating lowercase slugs for URLs
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Getting Started With XSLT
+ Advanced XPath Techniques
+
+```
+
+## Notes
+
+- Like `upper-case()`, this function uses Unicode default case mappings and is not locale-aware.
+- It does not modify digits, punctuation, or whitespace.
+- Combining `lower-case()` with `normalize-unicode()` is good practice when normalizing data from multiple sources before comparison.
+- In XSLT 1.0, the nearest equivalent is `translate()` with explicit letter-by-letter mapping, which is cumbersome for full Unicode support.
+
+## See also
+
+- [upper-case()](../xpath-upper-case)
+- [normalize-unicode()](../xpath-normalize-unicode)
+- [normalize-space()](../xpath-normalize-space)
diff --git a/site/content/xslt/functions/xpath-map-contains.md b/site/content/xslt/functions/xpath-map-contains.md
new file mode 100644
index 00000000..daf093e0
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-contains.md
@@ -0,0 +1,115 @@
+---
+title: "map:contains()"
+description: "Returns true if a map contains an entry with the specified key, false otherwise."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:contains(map, key)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:contains()` tests whether a map has an entry for a given key. The key comparison uses the same rules as map lookup (XDM equality for atomic values). This is preferable to checking `map:get()` for the empty sequence, because a key may legitimately map to the empty sequence.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map(*) | Yes | The map to test. |
+| `key` | xs:anyAtomicType | Yes | The key to look for. |
+
+## Return value
+
+`xs:boolean` — `true` if the map contains the key, `false` otherwise.
+
+## Examples
+
+### Safe conditional lookup
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ true
+ false
+ true
+
+```
+
+### Filtering a map by known keys
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice
+ 30
+ Paris
+
+```
+
+## Notes
+
+- Use `map:contains()` instead of `exists(map:get(...))` when a key may map to the empty sequence `()`.
+- Key comparison is type-aware: `map:contains($m, 1)` and `map:contains($m, '1')` are different lookups.
+- For checking multiple keys, combine with `every ... satisfies` or `some ... satisfies`.
+
+## See also
+
+- [map:get()](../xpath-map-get)
+- [map:keys()](../xpath-map-keys)
+- [map:size()](../xpath-map-size)
+- [map:put()](../xpath-map-put)
+- [xsl:map](../xsl-map)
diff --git a/site/content/xslt/functions/xpath-map-entry.md b/site/content/xslt/functions/xpath-map-entry.md
new file mode 100644
index 00000000..4f4ab99c
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-entry.md
@@ -0,0 +1,120 @@
+---
+title: "map:entry()"
+description: "Creates a singleton map containing exactly one key-value pair."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:entry(key, value)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:entry()` constructs a map with a single key-value entry. It is primarily useful when building maps programmatically — for example, inside `for` expressions or `fold-left()` accumulations — and then combining the singleton maps with `map:merge()`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `key` | xs:anyAtomicType | Yes | The key of the entry. |
+| `value` | item()* | Yes | The value to associate with the key. |
+
+## Return value
+
+`map(xs:anyAtomicType, item()*)` — a singleton map with one entry.
+
+## Examples
+
+### Building a map from XML nodes
+
+**Input XML:**
+```xml
+
+
+ example.com
+ 443
+ true
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ example.com
+ 443
+ true
+
+```
+
+### Accumulating a frequency map
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ bird
+ dog
+ cat
+
+```
+
+## Notes
+
+- `map:entry($k, $v)` is equivalent to the map constructor `map{$k: $v}`.
+- Particularly useful inside `for` expressions where the map constructor syntax is awkward.
+- Combine multiple `map:entry()` results with `map:merge()` to build larger maps.
+
+## See also
+
+- [map:get()](../xpath-map-get)
+- [map:put()](../xpath-map-put)
+- [map:merge()](../xpath-map-merge)
+- [xsl:map](../xsl-map)
+- [xsl:map-entry](../xsl-map-entry)
diff --git a/site/content/xslt/functions/xpath-map-get.md b/site/content/xslt/functions/xpath-map-get.md
new file mode 100644
index 00000000..cbb8df85
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-get.md
@@ -0,0 +1,115 @@
+---
+title: "map:get()"
+description: "Returns the value associated with a key in a map, or the empty sequence if the key is not present."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:get(map, key)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:get()` retrieves the value associated with a given key in a map. If the key does not exist, the empty sequence is returned — not an error. Because the empty sequence can also be a legitimate value, use `map:contains()` to distinguish "key absent" from "key maps to empty sequence".
+
+An alternative shorthand is `$map($key)` using function-call syntax on a map.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map(*) | Yes | The map to look up. |
+| `key` | xs:anyAtomicType | Yes | The key whose value is to be retrieved. |
+
+## Return value
+
+`item()*` — the value associated with the key, or the empty sequence if absent.
+
+## Examples
+
+### Basic map lookup
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Paris
+ Tokyo
+ Unknown
+
+```
+
+### Using function-call shorthand $map($key)
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+ - apple:
+ - banana:
+
+
+
+```
+
+**Output:**
+```xml
+
+ - apple: 0.99
+ - banana: 0.59
+
+```
+
+## Notes
+
+- `map:get()` and `$map($key)` are equivalent; the shorthand is more concise for inline expressions.
+- Returns the empty sequence (not an error) for missing keys; use `map:contains()` when you need to distinguish absence from an empty-sequence value.
+- Key comparison is type-aware: `xs:integer(1)` and `xs:string('1')` are different keys.
+
+## See also
+
+- [map:contains()](../xpath-map-contains)
+- [map:put()](../xpath-map-put)
+- [map:keys()](../xpath-map-keys)
+- [map:entry()](../xpath-map-entry)
+- [xsl:map](../xsl-map)
+- [xsl:map-entry](../xsl-map-entry)
diff --git a/site/content/xslt/functions/xpath-map-keys.md b/site/content/xslt/functions/xpath-map-keys.md
new file mode 100644
index 00000000..b6df11f7
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-keys.md
@@ -0,0 +1,112 @@
+---
+title: "map:keys()"
+description: "Returns all keys of a map as a sequence of atomic values in implementation-defined order."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:keys(map)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:keys()` returns a sequence containing all the keys present in a map. The order of keys in the result is implementation-defined and should not be relied upon. Keys are always atomic values (`xs:anyAtomicType`). For an empty map, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map(*) | Yes | The map whose keys are to be returned. |
+
+## Return value
+
+`xs:anyAtomicType*` — a sequence of all keys in the map; empty sequence for an empty map.
+
+## Examples
+
+### Iterating over all map keys
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+### Converting a map to XML elements
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ en
+ dark
+ 3.0
+
+```
+
+## Notes
+
+- The order of keys is not guaranteed; wrap with `sort()` for deterministic output.
+- Keys can be any atomic type: `xs:string`, `xs:integer`, `xs:date`, etc.
+- Duplicate keys cannot exist in a map, so `count(map:keys($m))` always equals `map:size($m)`.
+
+## See also
+
+- [map:get()](../xpath-map-get)
+- [map:contains()](../xpath-map-contains)
+- [map:size()](../xpath-map-size)
+- [map:merge()](../xpath-map-merge)
+- [xsl:map](../xsl-map)
diff --git a/site/content/xslt/functions/xpath-map-merge.md b/site/content/xslt/functions/xpath-map-merge.md
new file mode 100644
index 00000000..99453056
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-merge.md
@@ -0,0 +1,111 @@
+---
+title: "map:merge()"
+description: "Merges multiple maps into one, with duplicate key handling controlled by an options map."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:merge(maps, options?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:merge()` combines a sequence of maps into a single map. When two or more maps share the same key, the behavior is controlled by the `duplicates` option. The function is immutable — the input maps are not modified; a new map is returned.
+
+The `duplicates` option accepts: `"reject"` (error), `"use-first"`, `"use-last"` (default), `"combine"` (values become a sequence), or `"unspecified"`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `maps` | map(*)* | Yes | A sequence of maps to merge. |
+| `options` | map(xs:string, item())? | No | Options map; key `"duplicates"` controls duplicate handling. |
+
+## Return value
+
+`map(*)` — a new map containing all entries from the input maps.
+
+## Examples
+
+### Merging two maps with use-last (default)
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ red
+ medium
+ 5
+
+```
+
+### Merging with combine to accumulate duplicate values
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ xslt
+ xpath
+
+```
+
+## Notes
+
+- The default duplicate behavior (`use-last`) means later maps in the input sequence win.
+- `"reject"` causes `err:FOJS0003` when a duplicate key is encountered.
+- `map:merge()` also accepts an empty sequence, returning an empty map.
+- Maps are immutable in XDM; merge always produces a new map.
+
+## See also
+
+- [map:put()](../xpath-map-put)
+- [map:remove()](../xpath-map-remove)
+- [map:get()](../xpath-map-get)
+- [map:keys()](../xpath-map-keys)
+- [map:size()](../xpath-map-size)
+- [xsl:map](../xsl-map)
diff --git a/site/content/xslt/functions/xpath-map-put.md b/site/content/xslt/functions/xpath-map-put.md
new file mode 100644
index 00000000..e3ca5f3e
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-put.md
@@ -0,0 +1,119 @@
+---
+title: "map:put()"
+description: "Returns a new map with a key-value entry added or updated, leaving the original map unchanged."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:put(map, key, value)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:put()` produces a new map that is identical to the input map except that the given key is associated with the given value. If the key already exists, its value is replaced. If the key is new, the entry is added. Maps are immutable in XDM; the original map is never modified.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map(*) | Yes | The source map. |
+| `key` | xs:anyAtomicType | Yes | The key to add or update. |
+| `value` | item()* | Yes | The value to associate with the key. |
+
+## Return value
+
+`map(*)` — a new map with the specified key-value pair added or updated.
+
+## Examples
+
+### Adding and updating map entries
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ 99
+ 2
+ 3
+
+```
+
+### Building a map incrementally from XML
+
+**Input XML:**
+```xml
+
+
+ - localhost
+ - 8080
+ - true
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ localhost
+ 8080
+
+```
+
+## Notes
+
+- Maps are immutable; `map:put()` never modifies the original map.
+- Equivalent to `map:merge(($map, map:entry($key, $value)))` with `duplicates: use-last`.
+- Chain multiple `map:put()` calls to build up a map from individual entries.
+
+## See also
+
+- [map:get()](../xpath-map-get)
+- [map:remove()](../xpath-map-remove)
+- [map:entry()](../xpath-map-entry)
+- [map:merge()](../xpath-map-merge)
+- [xsl:map](../xsl-map)
+- [xsl:map-entry](../xsl-map-entry)
diff --git a/site/content/xslt/functions/xpath-map-remove.md b/site/content/xslt/functions/xpath-map-remove.md
new file mode 100644
index 00000000..0a47d352
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-remove.md
@@ -0,0 +1,114 @@
+---
+title: "map:remove()"
+description: "Returns a new map with one or more specified keys removed, leaving the original map unchanged."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:remove(map, keys)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:remove()` produces a new map that contains all entries from the input map except those whose keys appear in the `keys` sequence. If a key in `keys` is not present in the map, it is silently ignored. Maps are immutable; the original is not modified.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map(*) | Yes | The source map. |
+| `keys` | xs:anyAtomicType* | Yes | A sequence of keys to remove. |
+
+## Return value
+
+`map(*)` — a new map with the specified keys removed.
+
+## Examples
+
+### Removing a single key
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ alice@example.com
+ Alice
+
+```
+
+### Removing multiple keys at once
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ London
+ 1
+ Bob
+
+```
+
+## Notes
+
+- Removing a non-existent key is not an error; it is silently ignored.
+- Maps are immutable; `map:remove()` always returns a new map.
+- To remove all keys, use `map:remove($m, map:keys($m))`, which returns an empty map.
+
+## See also
+
+- [map:put()](../xpath-map-put)
+- [map:get()](../xpath-map-get)
+- [map:contains()](../xpath-map-contains)
+- [map:keys()](../xpath-map-keys)
+- [map:merge()](../xpath-map-merge)
+- [xsl:map](../xsl-map)
diff --git a/site/content/xslt/functions/xpath-map-size.md b/site/content/xslt/functions/xpath-map-size.md
new file mode 100644
index 00000000..b96c27ef
--- /dev/null
+++ b/site/content/xslt/functions/xpath-map-size.md
@@ -0,0 +1,113 @@
+---
+title: "map:size()"
+description: "Returns the number of key-value entries in a map."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "map function"
+syntax: "map:size(map)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`map:size()` returns the count of entries (key-value pairs) in a map as an `xs:integer`. An empty map returns `0`. This is the map equivalent of `count()` for sequences.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `map` | map(*) | Yes | The map whose entry count is to be returned. |
+
+## Return value
+
+`xs:integer` — the number of entries in the map; `0` for an empty map.
+
+## Examples
+
+### Counting entries in a map
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ 0
+
+```
+
+### Using size to validate a map before processing
+
+**Input XML:**
+```xml
+
+
+ example.com
+ 443
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 2
+ true
+
+```
+
+## Notes
+
+- `map:size()` is O(1) in most implementations.
+- Use `map:size($m) = 0` to check for an empty map (or compare with `map{}`).
+- The function counts top-level keys only; nested maps inside values count as one entry each.
+
+## See also
+
+- [map:keys()](../xpath-map-keys)
+- [map:get()](../xpath-map-get)
+- [map:contains()](../xpath-map-contains)
+- [map:merge()](../xpath-map-merge)
+- [xsl:map](../xsl-map)
diff --git a/site/content/xslt/functions/xpath-max.md b/site/content/xslt/functions/xpath-max.md
new file mode 100644
index 00000000..6eadc836
--- /dev/null
+++ b/site/content/xslt/functions/xpath-max.md
@@ -0,0 +1,111 @@
+---
+title: "max()"
+description: "Returns the largest value in a sequence of comparable items, optionally using a named collation for string comparison."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "numeric function"
+syntax: "max(sequence, collation?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`max()` returns the maximum value from a sequence. It works with any orderable atomic type: numeric types, strings, dates, times, and durations. All items in the sequence must be mutually comparable; mixing incompatible types raises a type error.
+
+When comparing strings, an optional collation URI controls ordering rules.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | xs:anyAtomicType* | Yes | Sequence of comparable values. |
+| `collation` | xs:string | No | Collation URI used for string comparison. Defaults to the default collation. |
+
+## Return value
+
+`xs:anyAtomicType?` — the largest item in the sequence according to the `gt` operator, or the empty sequence if the input is empty.
+
+## Examples
+
+### Maximum numeric value
+
+**Input XML:**
+```xml
+
+
+ 29.99
+ 149.00
+ 9.50
+ 74.95
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 149.00
+
+```
+
+### Latest date in a list
+
+**Input XML:**
+```xml
+
+
+ 2026-05-01
+ 2026-04-15
+ 2026-06-30
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+2026-06-30
+```
+
+## Notes
+
+- Returns the empty sequence (not an error) when the input sequence is empty.
+- `NaN` propagates: if any item is `xs:double('NaN')`, the result is `NaN`.
+- The collation parameter is only meaningful for string sequences.
+- Equivalent to sorting descending and taking the first item, but more concise and efficient.
+
+## See also
+
+- [min()](../xpath-min)
+- [avg()](../xpath-avg)
+- [abs()](../xpath-abs)
diff --git a/site/content/xslt/functions/xpath-min.md b/site/content/xslt/functions/xpath-min.md
new file mode 100644
index 00000000..35c82845
--- /dev/null
+++ b/site/content/xslt/functions/xpath-min.md
@@ -0,0 +1,111 @@
+---
+title: "min()"
+description: "Returns the smallest value in a sequence of comparable items, optionally using a named collation for string comparison."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "numeric function"
+syntax: "min(sequence, collation?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`min()` returns the minimum value from a sequence. It works with any orderable atomic type: numeric types, strings, dates, times, and durations. All items in the sequence must be mutually comparable; mixing incompatible types raises an error.
+
+When comparing strings, an optional collation URI controls ordering rules.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | xs:anyAtomicType* | Yes | Sequence of comparable values. |
+| `collation` | xs:string | No | Collation URI used for string comparison. Defaults to the default collation. |
+
+## Return value
+
+`xs:anyAtomicType?` — the smallest item in the sequence according to the `lt` operator, or the empty sequence if the input is empty.
+
+## Examples
+
+### Minimum numeric value
+
+**Input XML:**
+```xml
+
+
+ 23.5
+ 18.0
+ 31.2
+ 15.7
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 15.7
+
+```
+
+### Earliest date in a sequence
+
+**Input XML:**
+```xml
+
+
+ Summer conference
+ Spring kickoff
+ Year-end review
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+2026-03-01
+```
+
+## Notes
+
+- Returns the empty sequence (not an error) when the input sequence is empty.
+- `NaN` propagates: if any item is `xs:double('NaN')`, the result is `NaN`.
+- Unlike XSLT 1.0 workarounds (`` then `[1]`), `min()` is a single expression and works with typed values.
+- The collation parameter is meaningful only for string sequences.
+
+## See also
+
+- [max()](../xpath-max)
+- [avg()](../xpath-avg)
+- [abs()](../xpath-abs)
diff --git a/site/content/xslt/functions/xpath-minutes-from-time.md b/site/content/xslt/functions/xpath-minutes-from-time.md
new file mode 100644
index 00000000..995f03fe
--- /dev/null
+++ b/site/content/xslt/functions/xpath-minutes-from-time.md
@@ -0,0 +1,98 @@
+---
+title: "minutes-from-time()"
+description: "Extracts the minutes component from an xs:time value as an xs:integer in the range 0–59."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "minutes-from-time(time)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`minutes-from-time()` returns the minutes component of an `xs:time` value as an `xs:integer` between 0 and 59. If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `time` | xs:time? | Yes | The time value from which to extract the minutes. |
+
+## Return value
+
+`xs:integer?` — integer from 0 to 59, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Format a time with zero-padded minutes
+
+**Input XML:**
+```xml
+
+
+ System started
+ Lunch break
+ Shutdown
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ System started
+ Lunch break
+ Shutdown
+
+```
+
+### Check if an appointment is on the hour
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The argument must be typed as `xs:time`. Cast string values with `xs:time(@attr)`.
+- Returns 0–59; does not include fractional minutes (those appear in the seconds component).
+- For `xs:dateTime` values, use `minutes-from-dateTime()`.
+
+## See also
+
+- [hours-from-time()](../xpath-hours-from-time)
+- [seconds-from-time()](../xpath-seconds-from-time)
+- [current-time()](../xpath-current-time)
diff --git a/site/content/xslt/functions/xpath-month-from-date.md b/site/content/xslt/functions/xpath-month-from-date.md
new file mode 100644
index 00000000..856be941
--- /dev/null
+++ b/site/content/xslt/functions/xpath-month-from-date.md
@@ -0,0 +1,103 @@
+---
+title: "month-from-date()"
+description: "Extracts the month component from an xs:date value as an xs:integer in the range 1–12."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "month-from-date(date)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`month-from-date()` returns the month component of an `xs:date` value as an `xs:integer` between 1 (January) and 12 (December). If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `date` | xs:date? | Yes | The date value from which to extract the month. |
+
+## Return value
+
+`xs:integer?` — integer from 1 to 12 representing the month, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Group events by month
+
+**Input XML:**
+```xml
+
+
+ Easter workshop
+ Spring conference
+ Summer launch
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Easter workshop
+ Spring conference
+
+
+ Summer launch
+
+
+```
+
+### Check if a date falls in the current month
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The argument must be typed as `xs:date`. Cast string attributes with `xs:date(@attr)`.
+- Month numbers are 1-based (January = 1, December = 12).
+- Use alongside `year-from-date()` when filtering by month to avoid false matches across years.
+
+## See also
+
+- [year-from-date()](../xpath-year-from-date)
+- [day-from-date()](../xpath-day-from-date)
+- [current-date()](../xpath-current-date)
diff --git a/site/content/xslt/functions/xpath-name.md b/site/content/xslt/functions/xpath-name.md
new file mode 100644
index 00000000..06ba9c14
--- /dev/null
+++ b/site/content/xslt/functions/xpath-name.md
@@ -0,0 +1,123 @@
+---
+title: "name()"
+description: "Returns the qualified name (including namespace prefix, if any) of a node as it appears in the source document."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "name(node?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`name()` returns the qualified name of a node — the same string that appears in the source document, including the namespace prefix if one was used. For an element declared as ``, `name()` returns `"xhtml:div"`.
+
+When called without an argument, it returns the qualified name of the context node. When called with a node-set, it returns the qualified name of the first node in document order.
+
+For nodes that have no name (text nodes, comment nodes, document nodes), `name()` returns the empty string `""`. Processing instruction nodes return the PI target.
+
+Note that the prefix returned by `name()` is the prefix used in the **source document**, which may differ from the prefix declared in the stylesheet. If you need a namespace-safe comparison, use `namespace-uri()` and `local-name()` separately rather than relying on prefix equality.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node-set | No | The node whose qualified name to return. Defaults to the context node. |
+
+## Return value
+
+`xs:string` — the qualified name of the node as used in the source document, or `""` for unnamed nodes.
+
+## Examples
+
+### Report element and attribute names
+
+**Input XML:**
+```xml
+
+
+
+ XML in Practice
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+### Dynamic dispatch based on element name
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ username
+ secret
+ email
+
+```
+
+## Notes
+
+- `name()` returns the prefix-qualified name as written in the source document. Two documents can use different prefixes for the same namespace URI; therefore, do not compare `name()` values across documents when namespaces are involved.
+- For namespace-safe identity comparisons, use `namespace-uri() = 'http://...' and local-name() = 'foo'`.
+- `name()` and `local-name()` return the same value for unprefixed nodes.
+- In XSLT 2.0+, `fn:name()` is unchanged but the argument must be zero or one node; node-sets with multiple items raise a type error.
+
+## See also
+
+- [local-name()](../xpath-local-name)
+- [namespace-uri()](../xpath-namespace-uri)
diff --git a/site/content/xslt/functions/xpath-namespace-uri-from-qname.md b/site/content/xslt/functions/xpath-namespace-uri-from-qname.md
new file mode 100644
index 00000000..dd347aef
--- /dev/null
+++ b/site/content/xslt/functions/xpath-namespace-uri-from-qname.md
@@ -0,0 +1,101 @@
+---
+title: "namespace-uri-from-QName()"
+description: "Returns the namespace URI part of an xs:QName value."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "QName function"
+syntax: "namespace-uri-from-QName(qname)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`namespace-uri-from-QName()` extracts the namespace URI from an `xs:QName` value. The URI is the string that uniquely identifies the namespace, not the prefix. If the QName has no namespace, the function returns a zero-length string. If the argument is the empty sequence, the empty sequence is returned.
+
+This function is part of the family of QName accessor functions that decompose an `xs:QName` into its three components: local name, namespace URI, and prefix. The namespace URI is the most stable component because prefixes can be remapped, whereas namespace URIs are authoritative identifiers.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `qname` | xs:QName? | Yes | The QName from which to extract the namespace URI. |
+
+## Return value
+
+`xs:anyURI?` — the namespace URI of the QName, or the empty string if the QName has no namespace, or the empty sequence if the argument is empty.
+
+## Examples
+
+### Decomposing a QName
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ http://example.com/ns
+ widget
+ ex
+
+```
+
+### Checking the namespace of a node
+
+**Input XML:**
+```xml
+
+
+ content
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+ Namespace URI:
+
+
+
+```
+
+**Output:**
+```
+Namespace URI: http://myapp.example.com
+```
+
+## Notes
+
+- For a QName with no namespace (created with `QName('', 'localname')`), the function returns a zero-length `xs:anyURI`, not the empty sequence.
+- This function is the typed-value equivalent of calling `namespace-uri()` on a node; use `namespace-uri()` directly when working with nodes rather than `xs:QName` values.
+- Processors must not confuse a zero-length URI with the empty sequence; the two are distinct results.
+
+## See also
+
+- [local-name-from-QName()](../xpath-local-name-from-qname)
+- [prefix-from-QName()](../xpath-prefix-from-qname)
+- [resolve-QName()](../xpath-resolve-qname)
+- [QName()](../xpath-qname)
diff --git a/site/content/xslt/functions/xpath-namespace-uri.md b/site/content/xslt/functions/xpath-namespace-uri.md
new file mode 100644
index 00000000..a301560f
--- /dev/null
+++ b/site/content/xslt/functions/xpath-namespace-uri.md
@@ -0,0 +1,120 @@
+---
+title: "namespace-uri()"
+description: "Returns the namespace URI of a node's expanded name, or an empty string if the node has no namespace."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "namespace-uri(node?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`namespace-uri()` returns the namespace URI part of a node's expanded name. For an element ``, `namespace-uri()` returns `"http://www.w3.org/1999/xhtml"`.
+
+When called without an argument, it returns the namespace URI of the context node. When called with a node-set, it returns the namespace URI of the first node in document order.
+
+The function returns `""` (empty string) for:
+- Nodes with no namespace (unprefixed elements in a document without a default namespace, attributes without a prefix).
+- Nodes that inherently have no name: text nodes, comment nodes, document nodes.
+- The `xml:` prefix namespace (`http://www.w3.org/XML/1998/namespace`) is a valid URI that will be returned if the `xml:` prefix is used.
+
+`namespace-uri()` is essential for writing namespace-portable stylesheets that identify elements by their canonical URI rather than by the potentially varying prefix used in each source document.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node-set | No | The node to inspect. Defaults to the context node. |
+
+## Return value
+
+`xs:string` — the namespace URI of the node, or `""` if the node has no namespace.
+
+## Examples
+
+### Identify elements by namespace URI
+
+**Input XML:**
+```xml
+
+
+ XHTML paragraph
+ Plain paragraph
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+### Filter elements from a specific namespace
+
+**Input XML:**
+```xml
+
+
+ Section A
+ Plain div
+ Span
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Section A
+ - Span
+
+```
+
+## Notes
+
+- For attributes without a prefix, `namespace-uri()` returns `""` even if they are in scope inside a namespaced element. In XML, unprefixed attributes are not in any namespace.
+- The `xml:` prefix is predeclared and always maps to `http://www.w3.org/XML/1998/namespace`; `namespace-uri()` on an `xml:lang` attribute returns that URI.
+- Never rely on `name()` for namespace-aware matching across documents — always use `namespace-uri()` and `local-name()` together.
+- In XSLT 2.0+, `fn:namespace-uri()` is unchanged. The argument must be zero or one node.
+
+## See also
+
+- [local-name()](../xpath-local-name)
+- [name()](../xpath-name)
diff --git a/site/content/xslt/functions/xpath-nilled.md b/site/content/xslt/functions/xpath-nilled.md
new file mode 100644
index 00000000..e63b3f46
--- /dev/null
+++ b/site/content/xslt/functions/xpath-nilled.md
@@ -0,0 +1,96 @@
+---
+title: "nilled()"
+description: "Returns true if an element node is schema-validated and marked as nilled with xsi:nil=\"true\", otherwise returns false."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "nilled(node?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`nilled()` returns `xs:boolean` `true` if the argument is an element node that has been schema-validated and has its **nilled property** set — i.e., the element carries `xsi:nil="true"` and its schema type permits nilling.
+
+For elements that have not been schema-validated, or for non-element nodes, the function returns `false`. If the argument is the empty sequence, the empty sequence is returned.
+
+In practice, `nilled()` is used with schema-aware processors (such as Saxon-EE) to distinguish a genuinely absent value (`xsi:nil="true"`) from an element that is simply empty.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node()? | No | The node to test. Defaults to the context node. |
+
+## Return value
+
+`xs:boolean?` — `true` if the element is nilled, `false` if it is not, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Filter out nilled elements
+
+**Input XML (schema-validated):**
+```xml
+
+
+ Alice
+
+ Charlie
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice
+ Charlie
+
+```
+
+### Report nil status of each element
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `nilled()` only returns `true` for schema-validated elements with `xsi:nil="true"` and a nillable type in the schema. Without schema validation, it always returns `false`.
+- For non-schema-aware processing, checking `@xsi:nil = 'true'` directly is a common alternative.
+- This function is defined in XPath 2.0 and is not available in XSLT 1.0.
+
+## See also
+
+- [node-name()](../xpath-node-name)
+- [base-uri()](../xpath-base-uri)
diff --git a/site/content/xslt/functions/xpath-node-name.md b/site/content/xslt/functions/xpath-node-name.md
new file mode 100644
index 00000000..8255dee9
--- /dev/null
+++ b/site/content/xslt/functions/xpath-node-name.md
@@ -0,0 +1,103 @@
+---
+title: "node-name()"
+description: "Returns the name of a node as an xs:QName value, capturing both the namespace URI and the local name."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "node-name(node?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`node-name()` returns the name of an element or attribute node as an `xs:QName`. This is the typed equivalent of `name()` or `local-name()`: rather than returning a string, it returns a structured value from which you can extract the namespace URI, local name, and prefix separately.
+
+For text nodes, comments, and document nodes, the function returns the empty sequence. When called without an argument, the context node is used.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node()? | No | The node whose name is requested. Defaults to the context node. |
+
+## Return value
+
+`xs:QName?` — the qualified name of the node, or the empty sequence for text, comment, and document nodes.
+
+## Examples
+
+### Compare node names using QName equality
+
+**Input XML:**
+```xml
+
+
+ First
+ Second
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+### Dispatch based on qualified name
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Use `local-name-from-QName()`, `namespace-uri-from-QName()`, and `prefix-from-QName()` to decompose the returned `xs:QName`.
+- `node-name()` is namespace-aware; for a simple string name, `name()` or `local-name()` may be sufficient.
+- The prefix in the returned QName reflects the prefix used in the source document, which may differ from the prefix in the stylesheet.
+
+## See also
+
+- [local-name-from-QName()](../xpath-local-name-from-qname)
+- [namespace-uri-from-QName()](../xpath-namespace-uri-from-qname)
+- [QName()](../xpath-qname)
diff --git a/site/content/xslt/functions/xpath-normalize-space.md b/site/content/xslt/functions/xpath-normalize-space.md
new file mode 100644
index 00000000..4413aabf
--- /dev/null
+++ b/site/content/xslt/functions/xpath-normalize-space.md
@@ -0,0 +1,121 @@
+---
+title: "normalize-space()"
+description: "Strips leading and trailing whitespace from a string and collapses all internal whitespace sequences to a single space character."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "normalize-space(string?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`normalize-space()` performs three whitespace normalisation steps on its string argument:
+
+1. Strips all leading whitespace (spaces, tabs, newlines, carriage returns).
+2. Strips all trailing whitespace.
+3. Replaces each internal sequence of one or more whitespace characters with a single space (`U+0020`).
+
+When called without an argument, it normalises the string value of the context node.
+
+This function is indispensable when working with XML data that may contain arbitrary indentation or line breaks in element content — for example, multi-line address fields, code-generated XML, or content extracted from mixed-content elements.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string | No | The string to normalise. Defaults to the context node's string value. |
+
+## Return value
+
+`xs:string` — the normalised string with collapsed whitespace.
+
+## Examples
+
+### Clean up user-entered text
+
+**Input XML:**
+```xml
+
+
+ Alice Smith
+ Bob
+ Jones
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice Smith
+ Bob Jones
+
+```
+
+### Use in a predicate to filter blank elements
+
+**Input XML:**
+```xml
+
+
+ First line
+
+ Third line
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ First line
+ Third line
+
+```
+
+## Notes
+
+- `normalize-space('')` returns the empty string `""`.
+- The characters considered whitespace are: space (`U+0020`), tab (`U+0009`), carriage return (`U+000D`), and line feed (`U+000A`) — the same set as the XML `S` production.
+- `normalize-space()` does not affect non-whitespace characters; it only collapses runs of whitespace, including mixed sequences of tabs and newlines.
+- It is often used inside predicates: `element[normalize-space() != '']` selects only elements with non-blank text content.
+- In XSLT 2.0+, the function is unchanged. For more advanced whitespace handling (such as preserving significant spaces), use `xml:space="preserve"` or the XSLT `normalize-unicode()` function.
+
+## See also
+
+- [string()](../xpath-string)
+- [string-length()](../xpath-string-length)
+- [translate()](../xpath-translate)
diff --git a/site/content/xslt/functions/xpath-normalize-unicode.md b/site/content/xslt/functions/xpath-normalize-unicode.md
new file mode 100644
index 00000000..3e5e160a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-normalize-unicode.md
@@ -0,0 +1,104 @@
+---
+title: "normalize-unicode()"
+description: "Applies Unicode normalization (NFC, NFD, NFKC, NFKD, or FULLY-NORMALIZED) to a string, ensuring a canonical character representation."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "normalize-unicode(string, normalization-form?)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`normalize-unicode()` converts a string to a specified Unicode normalization form. Different normalization forms control whether composed or decomposed character representations are used, and whether compatibility equivalents are collapsed.
+
+The most common use case is ensuring consistent string comparison when data may come from different systems that represent the same character differently — for example, the letter `é` can be stored as a single precomposed codepoint (U+00E9) or as `e` followed by a combining accent (U+0065 U+0301).
+
+Normalization forms:
+
+| Form | Name | Description |
+|------|------|-------------|
+| `NFC` | Canonical Decomposition + Canonical Composition | Precomposed form (default, most common) |
+| `NFD` | Canonical Decomposition | Fully decomposed; base characters followed by combining marks |
+| `NFKC` | Compatibility Decomposition + Canonical Composition | Collapses compatibility variants (e.g., ligatures, width variants) |
+| `NFKD` | Compatibility Decomposition | Decomposed compatibility form |
+| `FULLY-NORMALIZED` | W3C XML extension | NFC with additional normalization of initial combining marks |
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | The string to normalize. |
+| `normalization-form` | xs:string | No | One of `NFC`, `NFD`, `NFKC`, `NFKD`, `FULLY-NORMALIZED`. Defaults to `NFC`. |
+
+## Return value
+
+`xs:string` — the input string in the requested normalization form. Returns `""` if `string` is an empty sequence.
+
+## Examples
+
+### Normalizing to NFC for consistent comparison
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Collapsing compatibility variants with NFKC
+
+**Input XML:**
+```xml
+
+
+
+ file²
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+file2
+```
+
+## Notes
+
+- NFC is the recommended normalization for most XML and web applications; it is the form used in HTML5 and most web APIs.
+- NFKC is useful for search and indexing where compatibility equivalents should be treated identically (e.g., full-width vs. half-width letters, ligatures).
+- NFD is mainly useful for low-level text processing or font rendering.
+- The normalization form argument is case-insensitive; `"nfc"` and `"NFC"` are equivalent.
+- If the argument is `""` (empty string), the NFC form (default) is applied.
+
+## See also
+
+- [upper-case()](../xpath-upper-case)
+- [lower-case()](../xpath-lower-case)
+- [codepoints-to-string()](../xpath-codepoints-to-string)
+- [string-to-codepoints()](../xpath-string-to-codepoints)
diff --git a/site/content/xslt/functions/xpath-not.md b/site/content/xslt/functions/xpath-not.md
new file mode 100644
index 00000000..c2702390
--- /dev/null
+++ b/site/content/xslt/functions/xpath-not.md
@@ -0,0 +1,117 @@
+---
+title: "not()"
+description: "Returns true if its boolean argument is false, and false if it is true — the logical negation of a boolean expression."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "boolean function"
+syntax: "not(boolean)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`not()` returns the logical negation of its argument. The argument is first converted to a boolean using the same rules as `boolean()`, and the result is the opposite value.
+
+It is one of the most frequently used functions in XPath predicates and `xsl:if` conditions, allowing you to express "if this node does not exist", "if this string is empty", or "if this condition does not hold".
+
+Because `not()` accepts any type and coerces it to boolean, you can negate node-set tests, string emptiness checks, and numeric comparisons in a single, readable expression.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `boolean` | any | Yes | The value to negate. Converted to boolean before negation. |
+
+## Return value
+
+`xs:boolean` — `true` if the argument converts to `false`, `false` if it converts to `true`.
+
+## Examples
+
+### Skip elements without a required attribute
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Gadget
+
+```
+
+### Conditional output based on element absence
+
+**Input XML:**
+```xml
+
+
+ - Book
+ - Pen
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ No discount applied.
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ No discount applied.
+ Book
+ Pen
+
+```
+
+## Notes
+
+- `not(condition)` is equivalent to writing `condition = false()` but is more idiomatic and concise.
+- To negate a compound condition, combine `not()` with `and`/`or`: `not(a or b)` means neither `a` nor `b` is true.
+- `not()` cannot be used as a shorthand for inequality (`!=`). Use `@attr != 'value'` rather than `not(@attr = 'value')` when comparing against multiple nodes, because the semantics differ for node-sets with more than one node.
+- In XSLT 2.0+ the function works identically; the argument may also be an empty sequence (which converts to `false`, so `not(())` returns `true`).
+
+## See also
+
+- [boolean()](../xpath-boolean)
+- [true()](../xpath-true)
+- [false()](../xpath-false)
diff --git a/site/content/xslt/functions/xpath-number.md b/site/content/xslt/functions/xpath-number.md
new file mode 100644
index 00000000..f46c986c
--- /dev/null
+++ b/site/content/xslt/functions/xpath-number.md
@@ -0,0 +1,127 @@
+---
+title: "number()"
+description: "Converts a string, boolean, or node-set to a number following XPath 1.0 type-conversion rules, returning NaN if the conversion fails."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "numeric function"
+syntax: "number(object?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`number()` converts its argument to a number using XPath 1.0 numeric conversion rules:
+
+- **String:** the string is stripped of leading and trailing whitespace and then parsed as a decimal number. If it cannot be parsed, the result is `NaN`.
+- **Boolean:** `true` converts to `1`, `false` converts to `0`.
+- **Node-set:** the node-set is first converted to its string value (same as calling `string()` on it), and then that string is converted to a number.
+- **Number:** returned unchanged.
+
+When called with no arguments, `number()` converts the string value of the context node.
+
+`number()` is essential when you need to perform arithmetic on element content or attribute values that XPath does not automatically treat as numbers, or when you want to explicitly coerce a value and test for `NaN` before proceeding.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `object` | any | No | Value to convert. Defaults to the context node's string value when omitted. |
+
+## Return value
+
+`xs:double` — the numeric value, or `NaN` if conversion fails.
+
+## Examples
+
+### Arithmetic on element content
+
+**Input XML:**
+```xml
+
+
+ 12.50
+ 7.99
+ 3.00
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 23.49
+ 25
+
+```
+
+### Guard against NaN before output
+
+**Input XML:**
+```xml
+
+
+ 42
+ N/A
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+ invalid
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - 42
+ - invalid
+
+```
+
+## Notes
+
+- The XPath 1.0 idiom to detect `NaN` is `$n != $n` (or equivalently `not($n = $n)`), because `NaN` is the only value not equal to itself.
+- Whitespace around numbers in element content is ignored: `number(' 3.14 ')` returns `3.14`.
+- Strings like `"Infinity"` and `"-Infinity"` are recognised by some processors as the numeric infinity values, but this is implementation-defined in XPath 1.0.
+- In XSLT 2.0+, `xs:double()`, `xs:integer()`, and `xs:decimal()` provide schema-aware type casting and raise errors on invalid input instead of returning `NaN`.
+
+## See also
+
+- [floor()](../xpath-floor)
+- [ceiling()](../xpath-ceiling)
+- [round()](../xpath-round)
+- [format-number()](../xpath-format-number)
diff --git a/site/content/xslt/functions/xpath-one-or-more.md b/site/content/xslt/functions/xpath-one-or-more.md
new file mode 100644
index 00000000..638b5540
--- /dev/null
+++ b/site/content/xslt/functions/xpath-one-or-more.md
@@ -0,0 +1,108 @@
+---
+title: "one-or-more()"
+description: "Asserts that the sequence contains one or more items; raises a dynamic error if the sequence is empty."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "one-or-more(sequence)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`one-or-more()` is a cardinality assertion function. It returns its argument unchanged when the sequence contains at least one item, and raises a dynamic error (`FORG0004`) if the sequence is empty. The function has no effect on sequences of two or more items.
+
+Use `one-or-more()` to document and enforce the assumption that a set of nodes must not be empty — for example when deriving a result from a required configuration element, or when a stylesheet would produce meaningless output if no input nodes matched. Asserting this explicitly makes the stylesheet self-documenting and avoids silent failures.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence that must contain one or more items. |
+
+## Return value
+
+`item()+` — the original sequence, unchanged. Raises `FORG0004` if the sequence is empty.
+
+## Examples
+
+### Enforcing required configuration
+
+**Input XML:**
+```xml
+
+
+ https://api.example.com
+ https://backup.example.com
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ https://api.example.com
+ https://backup.example.com
+
+```
+
+### Combining with string-join
+
+**Input XML:**
+```xml
+
+
+ xslt
+ xml
+ xpath
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+xslt, xml, xpath
+```
+
+## Notes
+
+- The error code raised for an empty sequence is `err:FORG0004`.
+- `one-or-more()` is the XPath equivalent of a database `NOT NULL` or `EXISTS` constraint applied at transformation time.
+- When the stylesheet is intended to run against schema-validated documents, `one-or-more()` duplicates validation that the schema already performs; its value is greatest in schema-free environments.
+- Use `zero-or-one()` when zero items is acceptable, and `exactly-one()` when the count must be precisely one.
+
+## See also
+
+- [exactly-one()](../xpath-exactly-one)
+- [zero-or-one()](../xpath-zero-or-one)
+- [error()](../xpath-error)
+- [empty()](../xpath-empty)
diff --git a/site/content/xslt/functions/xpath-outermost.md b/site/content/xslt/functions/xpath-outermost.md
new file mode 100644
index 00000000..66ee2c5a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-outermost.md
@@ -0,0 +1,104 @@
+---
+title: "outermost()"
+description: "Returns the nodes from the input that are not descendants of any other node in the input sequence."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "outermost(nodes)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`outermost()` filters a sequence of nodes to keep only those that are not descendants of any other node in the same sequence. It removes any node that has an ancestor also in the sequence, keeping only the highest-level nodes.
+
+The result is returned in document order. `outermost()` is the complement of `innermost()`: where `innermost()` retains the deepest nodes, `outermost()` retains the shallowest ancestors. The function is useful for deduplicating overlapping selections and for determining the roots of a set of subtrees.
+
+A common use case is normalizing the result of multiple union expressions where some selected nodes are contained within others — `outermost()` strips the redundant descendants, leaving only the minimal covering set.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `nodes` | node()* | Yes | The sequence of nodes to filter. |
+
+## Return value
+
+`node()*` — the subset of input nodes that have no ancestors in the input sequence, in document order.
+
+## Examples
+
+### Finding the top-level selected nodes
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+### Deduplicating subtree roots
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ outermost nodes
+
+
+```
+
+**Output:**
+```
+2 outermost nodes
+```
+
+## Notes
+
+- If no node in the sequence is a descendant of any other, `outermost()` returns all nodes in document order.
+- `outermost()` is particularly useful when preparing a node-set for `xsl:copy-of` where copying an ancestor would duplicate its descendants.
+- The result is always in document order regardless of the input order.
+- The function was introduced in XPath 3.0 / XSLT 3.0 alongside the general expansion of sequence manipulation functions.
+
+## See also
+
+- [innermost()](../xpath-innermost)
+- [has-children()](../xpath-has-children)
+- [path()](../xpath-path)
diff --git a/site/content/xslt/functions/xpath-parse-json.md b/site/content/xslt/functions/xpath-parse-json.md
new file mode 100644
index 00000000..e59cd77f
--- /dev/null
+++ b/site/content/xslt/functions/xpath-parse-json.md
@@ -0,0 +1,115 @@
+---
+title: "parse-json()"
+description: "Parses a JSON string and returns the result as an XDM map, array, string, number, boolean, or empty sequence."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "JSON function"
+syntax: "parse-json(string, options?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`parse-json()` converts a JSON string into XDM values following the mapping defined in the XPath 3.1 specification: JSON objects become XDM maps, JSON arrays become XDM arrays, JSON strings become `xs:string`, JSON numbers become `xs:double`, JSON booleans become `xs:boolean`, and JSON `null` becomes the empty sequence.
+
+The optional `options` argument is an XDM map controlling parsing behavior. The most commonly used option is `"liberal"` (a boolean that allows relaxed JSON syntax), and `"duplicates"` (controlling how duplicate object keys are handled: `"reject"`, `"use-first"`, or `"use-last"`).
+
+The function is the inverse of `xml-to-json()` combined with `parse-xml()`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | A valid JSON string to parse. Returns empty sequence if the input is the empty sequence. |
+| `options` | map(xs:string, item())? | No | A map of parsing options such as `"liberal"` and `"duplicates"`. |
+
+## Return value
+
+`item()?` — an XDM map, array, string, double, boolean, or the empty sequence (for JSON null), depending on the JSON content.
+
+## Examples
+
+### Parsing a JSON object
+
+**Input XML:**
+```xml
+
+
+ {"name": "Alice", "age": 30, "active": true}
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alice
+ 30
+ true
+
+```
+
+### Parsing a JSON array
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 1
+ 2
+ 3
+ 4
+ 5
+
+```
+
+## Notes
+
+- JSON numbers are mapped to `xs:double`; large integers may lose precision. Use the `"number-parser"` option in XPath 3.1 to supply a custom number converter.
+- JSON `null` maps to the empty sequence, not to a special null value. This means a JSON object with a `null` value and a missing key are indistinguishable after parsing with the default options.
+- If the input string is not valid JSON, a dynamic error is raised unless `"liberal": true()` is set.
+- The `"duplicates"` option defaults to `"use-first"` in most processors.
+
+## See also
+
+- [json-doc()](../xpath-json-doc)
+- [json-to-xml()](../xpath-json-to-xml)
+- [xml-to-json()](../xpath-xml-to-json)
+- [serialize()](../xpath-serialize)
diff --git a/site/content/xslt/functions/xpath-parse-xml-fragment.md b/site/content/xslt/functions/xpath-parse-xml-fragment.md
new file mode 100644
index 00000000..501d10a7
--- /dev/null
+++ b/site/content/xslt/functions/xpath-parse-xml-fragment.md
@@ -0,0 +1,97 @@
+---
+title: "parse-xml-fragment()"
+description: "Parses a well-balanced XML fragment string and returns it as a document node, allowing multiple top-level nodes."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "parse-xml-fragment(string)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`parse-xml-fragment()` parses a string that may contain **zero or more** XML nodes at the top level — in contrast to `parse-xml()`, which requires exactly one root element. The result is a document node whose children are the parsed nodes.
+
+The input must be **well-balanced**: every start tag must have a matching end tag, but a single root element is not required. The string may contain elements, text nodes, comments, and processing instructions at the top level.
+
+This function is part of XPath 3.0 but is supported by Saxon 9.x and later with XSLT 2.0 stylesheets.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | A string containing a well-balanced XML fragment. |
+
+## Return value
+
+`document-node()` — a document node containing the parsed content as children, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Parse an inline HTML fragment
+
+**Input XML:**
+```xml
+
+
+ Hello world
Second paragraph
]]>
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 2
+ Hello world
+ Second paragraph
+
+```
+
+### Merge stored XML fragments
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Unlike `parse-xml()`, the input does not need a single root element, making it suitable for HTML body fragments or partial XML documents stored in database fields.
+- The resulting document node has no document URI.
+- If the string is not well-balanced (unmatched tags), the function raises a dynamic error.
+- Available in Saxon 9.x+ with `version="2.0"` stylesheets; formally part of XPath 3.0.
+
+## See also
+
+- [parse-xml()](../xpath-parse-xml)
+- [document-uri()](../xpath-document-uri)
diff --git a/site/content/xslt/functions/xpath-parse-xml.md b/site/content/xslt/functions/xpath-parse-xml.md
new file mode 100644
index 00000000..d77fcfdc
--- /dev/null
+++ b/site/content/xslt/functions/xpath-parse-xml.md
@@ -0,0 +1,97 @@
+---
+title: "parse-xml()"
+description: "Parses a well-formed XML string and returns it as a new document node, usable like any other loaded XML document."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "parse-xml(string)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`parse-xml()` takes a string containing a well-formed XML document and returns a new **document node**. The resulting tree can be navigated with XPath expressions just like a document loaded with `doc()` or `document()`.
+
+If the string is not a well-formed XML document, the function raises a dynamic error. For XML fragments (content without a single root element), use `parse-xml-fragment()` instead.
+
+`parse-xml()` is defined in XPath 3.0 but is widely supported in Saxon 9.x and later with XSLT 2.0 stylesheets.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | A string containing a complete, well-formed XML document. |
+
+## Return value
+
+`document-node()` — a new document node whose children are the parsed content, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Parse XML stored in an element
+
+**Input XML:**
+```xml
+
+
+ - Alpha
- Beta
]]>
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Alpha
+ - Beta
+
+```
+
+### Count elements in a dynamically built XML string
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+ <root><a/><b/><c/></root>
+
+
+
+
+```
+
+**Output:**
+```
+3
+```
+
+## Notes
+
+- `parse-xml()` requires the input to be a complete, well-formed document with a single root element. Use `parse-xml-fragment()` for fragments.
+- The resulting document node has no document URI (`document-uri()` returns the empty sequence).
+- Available in Saxon 9.x+ when using `version="2.0"` stylesheets; it is formally part of XPath 3.0.
+
+## See also
+
+- [parse-xml-fragment()](../xpath-parse-xml-fragment)
+- [document-uri()](../xpath-document-uri)
diff --git a/site/content/xslt/functions/xpath-path.md b/site/content/xslt/functions/xpath-path.md
new file mode 100644
index 00000000..e8fb6301
--- /dev/null
+++ b/site/content/xslt/functions/xpath-path.md
@@ -0,0 +1,103 @@
+---
+title: "path()"
+description: "Returns a string that is a valid XPath expression identifying the path from the root to the node."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "path(node?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`path()` returns a string representation of the absolute path from the document root to the given node. The returned string uses positional predicates to make the path unambiguous — for example `/doc/section[2]/para[1]`. The string is a valid XPath expression that, when evaluated in the context of the same document, would select the same node.
+
+When called without arguments, the function uses the context node. The result uses namespace-prefixed element and attribute names when necessary, with prefixes drawn from the in-scope namespace bindings. The exact form of the path is implementation-defined but must be a syntactically valid XPath location path.
+
+`path()` is most useful for diagnostics, error messages, and audit trails that need to record which specific node triggered a condition.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | node()? | No | The node for which to compute the path. Defaults to the context node if omitted. |
+
+## Return value
+
+`xs:string?` — a string containing a valid absolute XPath path expression for the node, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Logging node paths during validation
+
+**Input XML:**
+```xml
+
+
+
+ -10
+
+
+ 25
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ Negative price detected
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Negative price detected
+
+```
+
+### Generating a path for a specific node
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+/catalog/product[2]/price[1]
+```
+
+## Notes
+
+- The format of the returned string is implementation-defined. Saxon uses positional predicates of the form `[n]` to disambiguate siblings.
+- `path()` applied to the document node returns the string `"/"`.
+- `path()` applied to an attribute node includes `@attributeName` notation.
+- For human-readable diagnostics, `path()` is preferable to constructing the path manually because it handles namespaces and position correctly.
+
+## See also
+
+- [has-children()](../xpath-has-children)
+- [innermost()](../xpath-innermost)
+- [outermost()](../xpath-outermost)
+- [trace()](../xpath-trace)
diff --git a/site/content/xslt/functions/xpath-prefix-from-qname.md b/site/content/xslt/functions/xpath-prefix-from-qname.md
new file mode 100644
index 00000000..c833cd80
--- /dev/null
+++ b/site/content/xslt/functions/xpath-prefix-from-qname.md
@@ -0,0 +1,100 @@
+---
+title: "prefix-from-QName()"
+description: "Returns the namespace prefix of an xs:QName value, or the empty sequence if the QName has no prefix."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "QName function"
+syntax: "prefix-from-QName(qname)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`prefix-from-QName()` returns the prefix component of an `xs:QName` value as an `xs:NCName`. The prefix is the part before the colon in a prefixed name. If the QName was created without a prefix — for example with `QName('http://example.com', 'item')` — the function returns the empty sequence, not a zero-length string.
+
+Prefixes are not inherently meaningful in XML; what matters is the namespace URI. Consequently this function is primarily used for producing human-readable output or for round-tripping serialized QNames back to string form. Do not use prefix equality to compare namespaces; use `namespace-uri-from-QName()` instead.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `qname` | xs:QName? | Yes | The QName from which to extract the prefix. |
+
+## Return value
+
+`xs:NCName?` — the prefix of the QName, or the empty sequence if the QName has no prefix or the argument is the empty sequence.
+
+## Examples
+
+### Extracting prefix from a constructed QName
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ ex
+ none
+
+```
+
+### Round-tripping a QName to string
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+ex:order
+```
+
+## Notes
+
+- The prefix is part of the `xs:QName` value only if it was present when the QName was constructed; `QName('http://example.com', 'item')` creates a QName with no prefix.
+- Avoid using prefix equality as a substitute for namespace URI equality. Two QNames with different prefixes bound to the same namespace URI are semantically identical.
+- `prefix-from-QName()` returns the empty sequence (not an empty string) when no prefix is present. Check with `exists()` rather than comparing to `''`.
+
+## See also
+
+- [local-name-from-QName()](../xpath-local-name-from-qname)
+- [namespace-uri-from-QName()](../xpath-namespace-uri-from-qname)
+- [resolve-QName()](../xpath-resolve-qname)
+- [QName()](../xpath-qname)
diff --git a/site/content/xslt/functions/xpath-qname.md b/site/content/xslt/functions/xpath-qname.md
new file mode 100644
index 00000000..a49ebe75
--- /dev/null
+++ b/site/content/xslt/functions/xpath-qname.md
@@ -0,0 +1,97 @@
+---
+title: "QName()"
+description: "Constructs an xs:QName value from a namespace URI and a lexical qualified name string."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "QName function"
+syntax: "QName(namespace-uri, lexical-qname)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`QName()` creates an `xs:QName` value by combining a namespace URI string with a lexical qualified name (which may include a prefix). This is the primary way to construct typed QName values dynamically in XPath 2.0.
+
+The resulting `xs:QName` can be used for namespace-aware name comparisons, passed to functions like `node-name()`, and used with `element-available()` or `type-available()`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `namespace-uri` | xs:string? | Yes | The namespace URI. Pass an empty string `""` for no namespace. |
+| `lexical-qname` | xs:string | Yes | A lexical qualified name, optionally including a prefix (e.g., `"xs:date"` or `"item"`). |
+
+## Return value
+
+`xs:QName` — the constructed QName with the given namespace URI, local name, and prefix.
+
+## Examples
+
+### Compare a node's name to a constructed QName
+
+**Input XML:**
+```xml
+
+
+ Click me
+ Enter value
+ Extra
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Click me
+ Enter value
+
+```
+
+### Dynamically create an element with a qualified name
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The prefix in the `lexical-qname` argument is stored in the `xs:QName` value but has no significance beyond readability — namespace-aware comparison uses the namespace URI and local name only.
+- If `namespace-uri` is empty (`""`) and the lexical name contains a colon, an error is raised.
+- `QName()` is the typed-value complement of `resolve-QName()`, which resolves namespace prefixes from an element's in-scope namespaces.
+
+## See also
+
+- [local-name-from-QName()](../xpath-local-name-from-qname)
+- [namespace-uri-from-QName()](../xpath-namespace-uri-from-qname)
+- [prefix-from-QName()](../xpath-prefix-from-qname)
+- [resolve-QName()](../xpath-resolve-qname)
diff --git a/site/content/xslt/functions/xpath-random-number-generator.md b/site/content/xslt/functions/xpath-random-number-generator.md
new file mode 100644
index 00000000..70d08dab
--- /dev/null
+++ b/site/content/xslt/functions/xpath-random-number-generator.md
@@ -0,0 +1,112 @@
+---
+title: "random-number-generator()"
+description: "Returns a deterministic pseudo-random number generator as a map, optionally seeded for reproducible results."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "random-number-generator(seed?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`random-number-generator()` returns a map containing a pseudo-random double in `[0, 1)`, a permutation function, and a `next` function that produces the next generator state. Because the output is deterministic for a given seed, transformations remain reproducible while still generating random-looking values.
+
+The returned map has three entries:
+- `"number"` — an `xs:double` in `[0, 1)`
+- `"next"` — a zero-argument function returning the next generator map
+- `"permute"` — a function that permutes a sequence pseudo-randomly
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `seed` | xs:anyAtomicType? | No | Optional seed value for reproducibility. Omitting gives an implementation-defined seed. |
+
+## Return value
+
+`map(xs:string, item())` — a map with keys `"number"`, `"next"`, and `"permute"`.
+
+## Examples
+
+### Generating a sequence of random numbers
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (values depend on implementation but are deterministic for seed 42):**
+```xml
+
+ 0.7275
+ 0.1234
+ 0.5891
+
+```
+
+### Shuffling a sequence with permute
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (deterministic for seed 99):**
+```xml
+
+ blue
+ yellow
+ red
+ purple
+ green
+
+```
+
+## Notes
+
+- The function is pure: the same seed always produces the same sequence, making transformations reproducible.
+- Without a seed, the implementation may use a random or time-based seed.
+- The `"permute"` entry produces a uniformly random permutation of the supplied sequence.
+- Chain `('next')()` calls to advance the generator state without mutating any variable.
+
+## See also
+
+- [for-each()](../xpath-for-each)
+- [sort()](../xpath-sort)
+- [fold-left()](../xpath-fold-left)
diff --git a/site/content/xslt/functions/xpath-regex-group.md b/site/content/xslt/functions/xpath-regex-group.md
new file mode 100644
index 00000000..2b5a38f9
--- /dev/null
+++ b/site/content/xslt/functions/xpath-regex-group.md
@@ -0,0 +1,125 @@
+---
+title: "regex-group()"
+description: "Returns the string matched by a numbered capture group of the current regex match inside xsl:analyze-string."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "regex-group(group-number)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`regex-group()` is available exclusively inside the body of `xsl:matching-substring`. It returns the substring captured by the parenthesized group identified by the integer argument:
+
+- `regex-group(0)` — the entire matched string.
+- `regex-group(1)` — the first parenthesized capture group.
+- `regex-group(2)` — the second parenthesized capture group, and so on.
+
+If the group number does not exist in the regex, or if the group did not participate in the match (e.g., it belongs to an unmatched alternative), the function returns an empty string `""`.
+
+`regex-group()` has no meaning outside `xsl:matching-substring` and should not be called in other contexts.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `group-number` | xs:integer | Yes | The capture group index: 0 for the full match, 1+ for numbered groups. |
+
+## Return value
+
+`xs:string` — the text captured by the specified group, or `""` if the group did not participate in the match.
+
+## Examples
+
+### Extracting date components
+
+**Input XML:**
+```xml
+
+
+ Launch on 2026-04-18 at HQ
+ Review on 2026-05-01 remotely
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+### Parsing key-value pairs
+
+**Input XML:**
+```xml
+
+color=blue;size=large;weight=12kg
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+## Notes
+
+- Groups are numbered by counting opening parentheses `(` left to right in the regex, starting from 1.
+- Non-capturing groups `(?:...)` are **not** supported in XPath regex; all parenthesized groups capture.
+- If a group is part of an alternation that did not match (e.g., `(a)|(b)` matched on `b` — group 1 returns `""`), the function returns `""` rather than raising an error.
+- `regex-group()` is a context function; its value changes for each match iteration of `xsl:analyze-string`.
+
+## See also
+
+- [xsl:analyze-string](../xsl-analyze-string)
+- [xsl:matching-substring](../xsl-matching-substring)
+- [matches()](../xpath-matches)
+- [replace()](../xpath-replace)
diff --git a/site/content/xslt/functions/xpath-remove.md b/site/content/xslt/functions/xpath-remove.md
new file mode 100644
index 00000000..878f4b0a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-remove.md
@@ -0,0 +1,108 @@
+---
+title: "remove()"
+description: "Returns a new sequence with the item at a specified 1-based position removed, without modifying the original sequence."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "remove(sequence, position)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`remove()` produces a new sequence that is identical to the input sequence except that the item at the specified 1-based `position` is omitted. Positions are 1-based. The original sequence is not modified.
+
+If `position` is less than 1 or greater than the length of the sequence, the entire sequence is returned unchanged — no error is raised.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The source sequence. |
+| `position` | xs:integer | Yes | The 1-based position of the item to remove. |
+
+## Return value
+
+`item()*` — the sequence with the item at `position` omitted. The length is `count($sequence) - 1` if `position` was valid.
+
+## Examples
+
+### Removing the first item
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+20, 30, 40, 50
+```
+
+### Removing a specific element from a node sequence
+
+**Input XML:**
+```xml
+
+
+ - Home
+ - About
+ - Blog
+ - Contact
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Home
+ About
+ Contact
+
+```
+
+## Notes
+
+- `remove()` only removes one item per call. To remove multiple items by position, chain calls or use `subsequence()` combined with sequence concatenation.
+- To remove items by value rather than position, use a filter predicate: `$seq[. != $value]`.
+- Out-of-range positions (< 1 or > length) are silently ignored; the full sequence is returned.
+- Equivalent to `($seq[position() lt $pos], $seq[position() gt $pos])` but more readable.
+
+## See also
+
+- [insert-before()](../xpath-insert-before)
+- [subsequence()](../xpath-subsequence)
+- [index-of()](../xpath-index-of)
+- [reverse()](../xpath-reverse)
diff --git a/site/content/xslt/functions/xpath-resolve-qname.md b/site/content/xslt/functions/xpath-resolve-qname.md
new file mode 100644
index 00000000..89e6d258
--- /dev/null
+++ b/site/content/xslt/functions/xpath-resolve-qname.md
@@ -0,0 +1,107 @@
+---
+title: "resolve-QName()"
+description: "Resolves a lexical QName string against the in-scope namespace bindings of a given element node."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "QName function"
+syntax: "resolve-QName(lexical-qname, element)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`resolve-QName()` converts a string containing a lexical QName (such as `"xs:integer"` or `"myns:product"`) into a typed `xs:QName` value by looking up the prefix in the namespace bindings of the supplied element node. The resulting `xs:QName` carries the namespace URI associated with the prefix in that element's scope.
+
+This function is particularly useful when an XML document stores QName-valued content as strings in attributes or text nodes — a common pattern in configuration files, WSDL documents, and schema instances. Without `resolve-QName()`, resolving the prefix to a URI requires manual namespace node traversal.
+
+If the lexical QName has no prefix, the resulting QName has no namespace (not the default namespace). If the prefix is not declared in scope on the element, a dynamic error is raised.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `lexical-qname` | xs:string? | Yes | A string containing the lexical QName to resolve. |
+| `element` | element() | Yes | The element node whose in-scope namespace bindings are used for resolution. |
+
+## Return value
+
+`xs:QName?` — the resolved QName, or the empty sequence if `lexical-qname` is the empty sequence.
+
+## Examples
+
+### Resolving QName content from an attribute
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+### Comparing resolved QNames
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+Matches xs:integer
+```
+
+## Notes
+
+- The element node provides the namespace context; the QName is resolved in the namespace scope of that specific element, including inherited namespace declarations.
+- A prefix that is not in scope on the supplied element raises `FOCA0002` (invalid value for cast or constructor).
+- To resolve a QName using the stylesheet's own namespace bindings rather than those in the source document, construct a QName with `QName()` directly.
+- `resolve-QName()` is the inverse of serializing a QName value to a prefixed string.
+
+## See also
+
+- [local-name-from-QName()](../xpath-local-name-from-qname)
+- [namespace-uri-from-QName()](../xpath-namespace-uri-from-qname)
+- [prefix-from-QName()](../xpath-prefix-from-qname)
+- [QName()](../xpath-qname)
diff --git a/site/content/xslt/functions/xpath-reverse.md b/site/content/xslt/functions/xpath-reverse.md
new file mode 100644
index 00000000..7fb412f4
--- /dev/null
+++ b/site/content/xslt/functions/xpath-reverse.md
@@ -0,0 +1,111 @@
+---
+title: "reverse()"
+description: "Returns the items of a sequence in reverse order."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "reverse(sequence)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`reverse()` returns a new sequence containing all the items from the argument sequence in the opposite order. The first item of the result is the last item of the input, and the last item of the result is the first item of the input. If the input sequence is empty, the empty sequence is returned.
+
+This function is purely order-based and does not sort or otherwise reorder items by value. It is useful when you need the last element of a node-set without using `[last()]`, or when you need to iterate over a sequence in reverse without reversing the natural document order.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence to reverse. |
+
+## Return value
+
+`item()*` — the same items as the input, in reverse order.
+
+## Examples
+
+### Reversing a node sequence
+
+**Input XML:**
+```xml
+
+
+ Connect
+ Authenticate
+ Query
+ Disconnect
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Disconnect
+ Query
+ Authenticate
+ Connect
+
+```
+
+### Getting the last child efficiently
+
+**Input XML:**
+```xml
+
+
+ First
+ Second
+ Latest
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+Latest
+```
+
+## Notes
+
+- `reverse()` does not sort by value; it literally inverts the order of items as they appear in the sequence.
+- When applied to node sequences, the resulting order is no longer document order. Predicates and axes applied to a reversed sequence operate on the reversed order.
+- An equivalent in XSLT 1.0 requires ` ` or a recursive template.
+- `reverse(reverse($seq))` is identical to `$seq`.
+
+## See also
+
+- [subsequence()](../xpath-subsequence)
+- [unordered()](../xpath-unordered)
+- [sort()](../xpath-sort)
diff --git a/site/content/xslt/functions/xpath-round.md b/site/content/xslt/functions/xpath-round.md
new file mode 100644
index 00000000..38aefa07
--- /dev/null
+++ b/site/content/xslt/functions/xpath-round.md
@@ -0,0 +1,119 @@
+---
+title: "round()"
+description: "Returns the integer closest to the argument, rounding half-values toward positive infinity (round half up)."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "numeric function"
+syntax: "round(number)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`round()` returns the integer nearest to its argument. When the fractional part is exactly `0.5`, XPath 1.0 uses **round-half-up** (toward positive infinity): `round(2.5)` returns `3`, and `round(-2.5)` returns `-2` (not `-3`).
+
+The argument is converted to a number via the same rules as `number()`. If the argument is already an integer, it is returned unchanged. Special values (`NaN`, `Infinity`, `-Infinity`) pass through unmodified.
+
+`round()` is the standard way to obtain a "nearest integer" result in XPath 1.0. It is frequently used to clean up the results of arithmetic expressions before displaying them, or to produce integer offsets for positioning calculations.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `number` | xs:double | Yes | The number to round to the nearest integer. |
+
+## Return value
+
+`xs:double` — the nearest integer, with ties rounded toward positive infinity.
+
+## Examples
+
+### Round calculated averages
+
+**Input XML:**
+```xml
+
+
+ 88
+ 92
+ 75
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 85
+ 85
+
+```
+
+### Demonstrate half-up tie-breaking
+
+**Input XML:**
+```xml
+
+
+ 2.5
+ -2.5
+ 3.4
+ 3.6
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ -2
+ 3
+ 4
+
+```
+
+## Notes
+
+- The tie-breaking rule (0.5 rounds up toward positive infinity) is defined in the XPath 1.0 specification and may differ from other languages: `round(-2.5)` is `-2`, not `-3`.
+- `round()` has no `precision` argument in XPath 1.0. To round to a specific number of decimal places, multiply, round, then divide: `round($n * 100) div 100` for two decimal places.
+- If the argument is `NaN`, the result is `NaN`.
+- In XSLT 2.0+, the `round()` function gains an optional second argument specifying the number of decimal places, eliminating the multiply-round-divide workaround.
+
+## See also
+
+- [floor()](../xpath-floor)
+- [ceiling()](../xpath-ceiling)
+- [number()](../xpath-number)
+- [format-number()](../xpath-format-number)
diff --git a/site/content/xslt/functions/xpath-seconds-from-time.md b/site/content/xslt/functions/xpath-seconds-from-time.md
new file mode 100644
index 00000000..f2770cad
--- /dev/null
+++ b/site/content/xslt/functions/xpath-seconds-from-time.md
@@ -0,0 +1,100 @@
+---
+title: "seconds-from-time()"
+description: "Extracts the seconds component from an xs:time value as an xs:decimal, including any fractional seconds."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "seconds-from-time(time)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`seconds-from-time()` returns the seconds component of an `xs:time` value as an `xs:decimal`. The value includes fractional seconds when present, and falls in the range 0 (inclusive) to 60 (exclusive, to allow for leap seconds). If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `time` | xs:time? | Yes | The time value from which to extract the seconds. |
+
+## Return value
+
+`xs:decimal?` — decimal value in the range [0, 60), or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Extract seconds from log timestamps
+
+**Input XML:**
+```xml
+
+
+ Request received
+ Processing started
+ Response sent
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Request received
+ Processing started
+ Response sent
+
+```
+
+### Round seconds to the nearest integer
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+31
+```
+
+## Notes
+
+- Returns `xs:decimal`, not `xs:integer`, so fractional seconds are preserved.
+- The upper bound is 60 (exclusive) to accommodate leap seconds, although most processors do not produce values above 59.
+- For `xs:dateTime` values, use `seconds-from-dateTime()`.
+
+## See also
+
+- [hours-from-time()](../xpath-hours-from-time)
+- [minutes-from-time()](../xpath-minutes-from-time)
+- [current-time()](../xpath-current-time)
diff --git a/site/content/xslt/functions/xpath-serialize.md b/site/content/xslt/functions/xpath-serialize.md
new file mode 100644
index 00000000..a9ea5950
--- /dev/null
+++ b/site/content/xslt/functions/xpath-serialize.md
@@ -0,0 +1,125 @@
+---
+title: "serialize()"
+description: "Serializes a node or sequence to a string using the W3C serialization specification and specified output parameters."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "JSON function"
+syntax: "serialize(nodes, output-declaration?)"
+tags: ["xslt", "reference", "xslt3", "xpath"]
+---
+
+## Description
+
+`serialize()` converts an XDM sequence of nodes or atomic values to a string, using the W3C XSLT/XQuery serialization specification. It is the programmatic equivalent of the output written by the stylesheet itself, but it produces a string value that can be stored in a variable, inserted into content, or written to a secondary result tree.
+
+The optional second argument is an output declaration: either an `xsl:output` element node (produced with `xsl:output` and referenced via the `output:` namespace) or a map of serialization parameter names to values. Common parameters include `method` (`"xml"`, `"html"`, `"text"`, `"json"`), `indent`, `encoding`, and `omit-xml-declaration`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `nodes` | `item()*` | Yes | The sequence of nodes or atomic values to serialize. |
+| `output-declaration` | `item()?` | No | An `xsl:output` element or a `map(xs:string, item()*)` of serialization parameters. |
+
+## Return value
+
+`xs:string` — the serialized representation of the input as a string.
+
+## Examples
+
+### Serializing an XML fragment to a string for embedding
+
+**Input XML:**
+```xml
+
+
+ Hello
+ World
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ <page>
+ <title>Hello</title>
+ <body>World</body>
+</page>
+ 47
+
+```
+
+### Serializing XML data to JSON format
+
+**Input XML:**
+```xml
+
+
+ - Widget
+ - 9.99
+ - true
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```json
+{
+ "name": "Widget",
+ "price": 9.99,
+ "in-stock": true
+}
+```
+
+## Notes
+
+- When the `method` is `"json"`, the input must be a single node in the W3C JSON-XML format (same as `xml-to-json()` accepts). Use `xml-to-json()` directly for this case if you do not need other serialization control.
+- `serialize()` is often used in combination with `result-document` alternatives: when you need the XML string inside the transformation rather than written to a file.
+- Atomic values in the input sequence are serialized using their string representation, separated by spaces by default.
+- The `map` form of the second argument uses the same parameter names as `xsl:output` attributes, but as strings: `"indent"`, `"method"`, `"omit-xml-declaration"`, `"encoding"`, etc.
+
+## See also
+
+- [xsl:output](../xsl-output)
+- [xml-to-json()](../xpath-xml-to-json)
diff --git a/site/content/xslt/functions/xpath-snapshot.md b/site/content/xslt/functions/xpath-snapshot.md
new file mode 100644
index 00000000..1e06b55a
--- /dev/null
+++ b/site/content/xslt/functions/xpath-snapshot.md
@@ -0,0 +1,113 @@
+---
+title: "snapshot()"
+description: "Returns a snapshot copy of the sequence, making streamed nodes available for multiple use."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "node function"
+syntax: "snapshot(sequence?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`snapshot()` returns a deep copy of its argument sequence, detached from the original document. Its primary purpose is in streaming mode: when a template is processing a streamed document, nodes are typically available only once and cannot be re-read. Calling `snapshot()` materializes those nodes into a persistent in-memory copy that can be used multiple times, stored in a variable, or passed to a function that requires grounded (non-streamed) nodes.
+
+Outside of streaming mode, `snapshot()` behaves identically to `copy-of()` and produces deep copies of all node items. Atomic values in the sequence are returned unchanged.
+
+When called without arguments in XSLT 3.0, the function snapshots the context item.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | No | The sequence to snapshot. Defaults to the context item if omitted. |
+
+## Return value
+
+`item()*` — a deep copy of the node items in the sequence; atomic values returned unchanged.
+
+## Examples
+
+### Capturing streamed nodes for reuse
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ 450
+
+```
+
+### Snapshot of the context item
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+## Notes
+
+- `snapshot()` is a no-op on atomic values; they are returned unchanged.
+- In non-streaming mode, `snapshot()` and `copy-of()` produce equivalent results.
+- Use `snapshot()` rather than `copy-of()` when the intent is specifically to escape the streaming constraint, as this communicates the purpose more clearly to readers.
+- The function was added in XPath 3.0 specifically to support the XSLT 3.0 streaming model.
+
+## See also
+
+- [copy-of()](../xpath-copy-of)
+- [accumulator-before()](../xpath-accumulator-before)
+- [accumulator-after()](../xpath-accumulator-after)
diff --git a/site/content/xslt/functions/xpath-sort.md b/site/content/xslt/functions/xpath-sort.md
new file mode 100644
index 00000000..1ab96e0e
--- /dev/null
+++ b/site/content/xslt/functions/xpath-sort.md
@@ -0,0 +1,113 @@
+---
+title: "sort()"
+description: "Sorts a sequence of items using an optional collation and key function, returning items in ascending order."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "higher-order function"
+syntax: "sort(sequence, collation?, key-function?)"
+tags: ["xslt", "reference", "xpath", "xslt3"]
+---
+
+## Description
+
+`sort()` sorts a sequence of items and returns them in ascending order. An optional collation URI controls string comparison, and an optional key function extracts the sort key from each item. This is the functional alternative to `xsl:sort` and can be used directly within XPath expressions.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence to sort. |
+| `collation` | xs:string? | No | URI of the collation to use for string comparison. Defaults to the default collation. |
+| `key-function` | function(item()) as xs:anyAtomicType* | No | Function that extracts the sort key from each item. Defaults to identity. |
+
+## Return value
+
+`item()*` — the items in ascending order according to the sort key and collation.
+
+## Examples
+
+### Sorting strings alphabetically
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ apple
+ banana
+ cherry
+ date
+
+```
+
+### Sorting XML nodes by a numeric attribute
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+## Notes
+
+- Sorting is stable: items with equal keys preserve their original relative order.
+- Pass `()` as the collation argument to use the default collation while still providing a key function.
+- For descending sort in XPath expressions, use `reverse(sort(...))`.
+- `sort()` is also available as `array:sort()` for sorting array members.
+- In XSLT templates, `xsl:sort` inside `xsl:for-each` or `xsl:apply-templates` remains an alternative.
+
+## See also
+
+- [for-each()](../xpath-for-each)
+- [filter()](../xpath-filter)
+- [fold-left()](../xpath-fold-left)
+- [array:sort()](../xpath-array-sort)
diff --git a/site/content/xslt/functions/xpath-starts-with.md b/site/content/xslt/functions/xpath-starts-with.md
new file mode 100644
index 00000000..3ca47ebd
--- /dev/null
+++ b/site/content/xslt/functions/xpath-starts-with.md
@@ -0,0 +1,119 @@
+---
+title: "starts-with()"
+description: "Returns true if the first string begins with the second string as an exact prefix, performing a case-sensitive comparison."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "starts-with(string, prefix)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`starts-with()` tests whether `string` begins with `prefix` and returns a boolean. Both arguments are converted to strings before the comparison, which is **case-sensitive** and based on Unicode code points.
+
+If `prefix` is the empty string `""`, the function always returns `true`, because every string (including the empty string) starts with the empty string.
+
+`starts-with()` is commonly used in predicates to select elements or attributes that share a naming convention, a URL scheme prefix, or any other known leading text. It is simpler and faster than the equivalent `substring()` comparison.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string | Yes | The string to test. |
+| `prefix` | xs:string | Yes | The expected prefix. |
+
+## Return value
+
+`xs:boolean` — `true` if `string` starts with `prefix`, `false` otherwise.
+
+## Examples
+
+### Filter elements by attribute prefix
+
+**Input XML:**
+```xml
+
+
+ Page 1
+ Page 2
+ Page 3
+ Files
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Page 1
+ Page 3
+
+```
+
+### Conditional processing based on prefix
+
+**Input XML:**
+```xml
+
+
+ ERR-001
+ OK-202
+ ERR-403
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ ERR-001
+ ERR-403
+
+```
+
+## Notes
+
+- The comparison is **case-sensitive**: `starts-with('Hello', 'he')` returns `false`. For case-insensitive prefix matching in XSLT 2.0+, use `starts-with(lower-case($s), 'he')`.
+- `starts-with($s, '')` always returns `true`.
+- XPath 1.0 has no `ends-with()` function. To test a suffix, use `substring($s, string-length($s) - string-length($suffix) + 1) = $suffix`, or use `ends-with()` in XSLT 2.0+.
+- `starts-with()` is equivalent to `substring($s, 1, string-length($prefix)) = $prefix` but far more readable.
+
+## See also
+
+- [contains()](../xpath-contains)
+- [substring-before()](../xpath-substring-before)
+- [substring-after()](../xpath-substring-after)
diff --git a/site/content/xslt/functions/xpath-static-base-uri.md b/site/content/xslt/functions/xpath-static-base-uri.md
new file mode 100644
index 00000000..585573ff
--- /dev/null
+++ b/site/content/xslt/functions/xpath-static-base-uri.md
@@ -0,0 +1,87 @@
+---
+title: "static-base-uri()"
+description: "Returns the static base URI of the stylesheet module as an xs:anyURI, i.e., the URI of the XSLT file being executed."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "static-base-uri()"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`static-base-uri()` returns the **static base URI** of the stylesheet module — the URI of the XSLT file in which the expression appears. This is determined at compile time from the location of the stylesheet, not at runtime from the source document.
+
+It is particularly useful for resolving relative URIs for resources (text files, secondary XML documents) that are located **relative to the stylesheet** rather than relative to the source document.
+
+If the stylesheet has no known base URI (e.g., it was passed as a string without a URI), the empty sequence is returned.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:anyURI?` — the static base URI of the stylesheet module, or the empty sequence if no base URI is available.
+
+## Examples
+
+### Load a resource file relative to the stylesheet
+
+**Stylesheet (located at `file:///xslt/report.xsl`):**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Log the stylesheet URI in the output
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```xml
+
+ ...
+
+```
+
+## Notes
+
+- `static-base-uri()` differs from `base-uri()`, which returns the base URI of a **source node** (affected by `xml:base`).
+- It differs from `document-uri()`, which returns the URI of a document node.
+- In a stylesheet with `` or ``, each module has its own static base URI, so `static-base-uri()` returns the URI of the module where the expression is written — not the main stylesheet's URI.
+
+## See also
+
+- [base-uri()](../xpath-base-uri)
+- [document-uri()](../xpath-document-uri)
diff --git a/site/content/xslt/functions/xpath-string-length.md b/site/content/xslt/functions/xpath-string-length.md
new file mode 100644
index 00000000..ed7df066
--- /dev/null
+++ b/site/content/xslt/functions/xpath-string-length.md
@@ -0,0 +1,116 @@
+---
+title: "string-length()"
+description: "Returns the number of characters in a string, or the length of the context node's string value when called with no argument."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "string-length(string?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`string-length()` returns the number of characters in its string argument. The argument is first converted to a string using `string()` rules. When called without an argument, it returns the character count of the context node's string value.
+
+In XPath 1.0, "characters" means Unicode code points. Surrogate pairs and multi-byte UTF-8 sequences each count as however many code points they represent (a supplementary character represented by two UTF-16 code units may count as one or two depending on the processor).
+
+`string-length()` is useful for validation (checking minimum or maximum field lengths), for computing substring offsets, and for filtering elements whose content exceeds or falls below a threshold.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string | No | The string to measure. Defaults to the context node's string value. |
+
+## Return value
+
+`xs:double` — the number of characters in the string (a non-negative integer represented as a double).
+
+## Examples
+
+### Filter elements by content length
+
+**Input XML:**
+```xml
+
+
+ hi
+ hello
+ extraordinary
+ ok
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - hello
+ - extraordinary
+
+```
+
+### Report field lengths
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+## Notes
+
+- `string-length('')` returns `0`. An empty element with no text children has `string-length()` of `0`.
+- The return value is a number (double), not an integer, although it will always be a whole number in practice.
+- `string-length()` counts the string value of the context node when called with no argument — for an element, that is all descendant text nodes concatenated.
+- For computing a right-aligned substring (e.g. the last N characters), combine with `substring()`: `substring($s, string-length($s) - N + 1)`.
+- In XSLT 2.0+, `fn:string-length()` operates identically but the argument must be a single string; passing a sequence of more than one item raises a type error.
+
+## See also
+
+- [string()](../xpath-string)
+- [normalize-space()](../xpath-normalize-space)
+- [substring()](../xpath-substring)
diff --git a/site/content/xslt/functions/xpath-string-to-codepoints.md b/site/content/xslt/functions/xpath-string-to-codepoints.md
new file mode 100644
index 00000000..ff00d8ef
--- /dev/null
+++ b/site/content/xslt/functions/xpath-string-to-codepoints.md
@@ -0,0 +1,111 @@
+---
+title: "string-to-codepoints()"
+description: "Returns a sequence of integers representing the Unicode codepoints of each character in a string."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "string-to-codepoints(string)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`string-to-codepoints()` decomposes a string into its individual Unicode characters and returns their integer codepoints as a sequence of `xs:integer` values. The sequence length equals the number of Unicode characters (codepoints) in the string, which may differ from the byte length in UTF-8 or UTF-16 encodings.
+
+It is the inverse of `codepoints-to-string()` and enables character-level manipulation — inspecting, filtering, or transforming individual characters by their numeric values.
+
+If the argument is an empty sequence or an empty string, the function returns an empty sequence.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | The string to decompose into codepoints. |
+
+## Return value
+
+`xs:integer*` — a sequence of Unicode codepoint integers, one per character.
+
+## Examples
+
+### Inspecting character codepoints
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+### Filtering non-ASCII characters
+
+**Input XML:**
+```xml
+
+
+ Héllo Wörld
+ Plain ASCII only
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Héllo Wörld
+ Plain ASCII only
+
+```
+
+## Notes
+
+- Each item in the returned sequence is the codepoint of one Unicode character, not one byte. For multi-byte UTF-8 characters (e.g., `©` is 2 bytes) the function still returns one integer.
+- Surrogate pairs as used in UTF-16 are presented as their actual codepoint (e.g., U+1F600 emoji returns `128512`, not two surrogate integers).
+- Combining with `codepoints-to-string()` allows lossless character-by-character transformations.
+- `count(string-to-codepoints($s))` gives the number of Unicode characters, equivalent to `string-length($s)`.
+
+## See also
+
+- [codepoints-to-string()](../xpath-codepoints-to-string)
+- [string-length()](../xpath-string-length)
+- [normalize-unicode()](../xpath-normalize-unicode)
diff --git a/site/content/xslt/functions/xpath-string.md b/site/content/xslt/functions/xpath-string.md
new file mode 100644
index 00000000..ecd493b5
--- /dev/null
+++ b/site/content/xslt/functions/xpath-string.md
@@ -0,0 +1,120 @@
+---
+title: "string()"
+description: "Converts a node-set, number, or boolean to its XPath string value, or returns the string value of the context node when called with no argument."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "string(object?)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`string()` converts its argument to a string using XPath 1.0 string-value rules:
+
+- **Node-set:** returns the string value of the first node in document order. For element nodes, this is the concatenation of all text-node descendants; for attribute nodes, the attribute value; for the document node, the concatenation of all text descendants.
+- **Number:** returns the canonical decimal representation. `NaN` becomes `"NaN"`, infinity becomes `"Infinity"`.
+- **Boolean:** `true` becomes `"true"`, `false` becomes `"false"`.
+- **String:** returned unchanged.
+
+When called with no arguments, `string()` returns the string value of the context node, equivalent to `string(.)`.
+
+`string()` is used to extract the textual content of complex elements (flattening all descendant text nodes into one string), to convert numbers or booleans for string comparison, or to force a node-set to a scalar string value.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `object` | any | No | Value to convert. Defaults to the context node when omitted. |
+
+## Return value
+
+`xs:string` — the string representation of the argument.
+
+## Examples
+
+### Extract concatenated text content of an element
+
+**Input XML:**
+```xml
+
+
+
+ First paragraph.
+ Second paragraph .
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ First paragraph.
+ Second paragraph.
+
+```
+
+### Convert numbers and booleans to strings
+
+**Input XML:**
+```xml
+
+
+ 5
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 5
+ true
+ false
+ NaN
+
+```
+
+## Notes
+
+- For a node-set with multiple nodes, `string()` only returns the value of the **first node** in document order. To concatenate all nodes, use `string-join()` (XSLT 2.0+) or iterate with `xsl:for-each`.
+- Calling `string()` on an element that contains mixed content (text and child elements) returns all descendant text nodes joined together, with no separators.
+- `string(0)` returns `"0"`, `string(-0)` returns `"0"` (negative zero is normalised).
+- In XSLT 2.0+, `string()` behaves similarly but the argument may be a sequence; if the sequence has more than one item, an error is raised unless using the XPath 2.0 `data()` or `string-join()` function instead.
+
+## See also
+
+- [string-length()](../xpath-string-length)
+- [normalize-space()](../xpath-normalize-space)
+- [concat()](../xpath-concat)
diff --git a/site/content/xslt/functions/xpath-subsequence.md b/site/content/xslt/functions/xpath-subsequence.md
new file mode 100644
index 00000000..4b695933
--- /dev/null
+++ b/site/content/xslt/functions/xpath-subsequence.md
@@ -0,0 +1,114 @@
+---
+title: "subsequence()"
+description: "Returns a contiguous subsequence of items starting at a 1-based position."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "subsequence(sequence, startingLoc, length?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`subsequence()` extracts a contiguous run of items from a sequence. The `startingLoc` parameter is 1-based: position 1 is the first item. If `length` is supplied, at most that many items are returned. If `length` is omitted, all items from `startingLoc` to the end of the sequence are returned.
+
+Positions outside the sequence bounds are handled gracefully: if `startingLoc` is less than 1 it is treated as 1; if `startingLoc` is beyond the end of the sequence the result is the empty sequence; if `length` would extend beyond the end of the sequence, only the available items are returned.
+
+`subsequence()` is the idiomatic XPath 2.0 alternative to the XSLT 1.0 `position()` and `last()` workaround, and is more readable than `$seq[position() ge $start and position() le $start + $len - 1]`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The source sequence. |
+| `startingLoc` | xs:double | Yes | 1-based starting position. Values less than 1 are treated as 1. |
+| `length` | xs:double | No | Maximum number of items to return. Omit to return all remaining items. |
+
+## Return value
+
+`item()*` — the selected contiguous subsequence, or the empty sequence if no items qualify.
+
+## Examples
+
+### Pagination: extracting a page of results
+
+**Input XML:**
+```xml
+
+
+ - A
- B
- C
+ - D
- E
- F
+ - G
- H
- I
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - D
+ - E
+ - F
+
+```
+
+### Taking the first N items
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - A
+ - B
+ - C
+
+```
+
+## Notes
+
+- The `startingLoc` and `length` parameters are `xs:double` rather than integer, which means `NaN`, `INF`, and fractional values are accepted. Fractional values are rounded to the nearest integer using round-half-to-even.
+- `subsequence($seq, 1)` is equivalent to `$seq` itself.
+- `subsequence($seq, 2)` removes the first item, equivalent to `tail($seq)` which is available in XPath 3.0.
+- For very large sequences, processors may optimize `subsequence()` to avoid materializing the entire sequence.
+
+## See also
+
+- [reverse()](../xpath-reverse)
+- [unordered()](../xpath-unordered)
+- [insert-before()](../xpath-insert-before)
+- [remove()](../xpath-remove)
diff --git a/site/content/xslt/functions/xpath-substring-after.md b/site/content/xslt/functions/xpath-substring-after.md
new file mode 100644
index 00000000..34f4dd42
--- /dev/null
+++ b/site/content/xslt/functions/xpath-substring-after.md
@@ -0,0 +1,117 @@
+---
+title: "substring-after()"
+description: "Returns the part of a string that appears after the first occurrence of a given separator substring."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "substring-after(string, separator)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`substring-after()` finds the first occurrence of `separator` in `string` and returns everything that follows it. If `separator` is not found, the function returns the empty string `""`. If `separator` is the empty string, the function returns the entire `string`.
+
+Both arguments are converted to strings before processing. The search is case-sensitive.
+
+`substring-after()` is the complement of `substring-before()` and together they provide the XPath 1.0 way to split a delimited string: extract the domain from an email address, the value from a `key=value` pair, or the path from a `scheme://authority/path` URI.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string | Yes | The string to search within. |
+| `separator` | xs:string | Yes | The delimiter to search for. |
+
+## Return value
+
+`xs:string` — the portion of `string` after the first occurrence of `separator`, or `""` if not found.
+
+## Examples
+
+### Extract the domain from an email address
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ example.com
+ company.org
+
+```
+
+### Extract a path segment after a known prefix
+
+**Input XML:**
+```xml
+
+
+ https://api.example.com/v1/users
+ https://api.example.com/v1/products
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ /v1/users
+ /v1/products
+
+```
+
+## Notes
+
+- If `separator` is not found in `string`, the result is `""` — not the original string. Use `contains()` first if you need to handle the not-found case differently.
+- Only the **first** occurrence of `separator` is used. To extract the portion after the last occurrence, nest `substring-after()` calls or use a recursive named template in XSLT 1.0.
+- `substring-after($s, '')` returns the full string `$s` (the empty string is found at position zero, so everything after it is the whole input).
+- In XSLT 2.0+, `tokenize()` splits a string into a sequence and is generally more convenient for repeated splitting.
+
+## See also
+
+- [substring-before()](../xpath-substring-before)
+- [starts-with()](../xpath-starts-with)
+- [contains()](../xpath-contains)
+- [substring()](../xpath-substring)
diff --git a/site/content/xslt/functions/xpath-substring-before.md b/site/content/xslt/functions/xpath-substring-before.md
new file mode 100644
index 00000000..34aa87fa
--- /dev/null
+++ b/site/content/xslt/functions/xpath-substring-before.md
@@ -0,0 +1,120 @@
+---
+title: "substring-before()"
+description: "Returns the part of a string that appears before the first occurrence of a given separator substring."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "substring-before(string, separator)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`substring-before()` finds the first occurrence of `separator` in `string` and returns everything that precedes it. If `separator` is not found, the function returns the empty string `""`. If `separator` is the empty string, the function also returns `""`.
+
+Both arguments are converted to strings before processing. The search is case-sensitive.
+
+`substring-before()` is the XPath 1.0 way to split a delimited string and extract the left-hand portion: usernames from `user@host` addresses, keys from `key=value` pairs, or path segments from URIs.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string | Yes | The string to search within. |
+| `separator` | xs:string | Yes | The delimiter to search for. |
+
+## Return value
+
+`xs:string` — the portion of `string` before the first occurrence of `separator`, or `""` if not found.
+
+## Examples
+
+### Extract username from an email address
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ alice
+ bob.smith
+
+```
+
+### Extract key from a key=value pair
+
+**Input XML:**
+```xml
+
+
+ color=blue
+ size=large
+ weight=1.5kg
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ color blue
+ size large
+ weight 1.5kg
+
+```
+
+## Notes
+
+- If `separator` does not appear in `string`, `substring-before()` returns `""` — not the original string. Use `contains()` first if you need to distinguish the "not found" case.
+- Only the **first** occurrence of `separator` is used. To split on the last occurrence, combine `substring-before()` with `substring-after()` and recursive templates or iterate with the `translate()` trick in XSLT 1.0.
+- `substring-before($s, '')` returns `""` as specified; this is a common source of confusion.
+- In XSLT 2.0+, `tokenize()` provides a cleaner way to split strings on delimiters, including regex-based separators.
+
+## See also
+
+- [substring-after()](../xpath-substring-after)
+- [starts-with()](../xpath-starts-with)
+- [contains()](../xpath-contains)
+- [substring()](../xpath-substring)
diff --git a/site/content/xslt/functions/xpath-system-property.md b/site/content/xslt/functions/xpath-system-property.md
new file mode 100644
index 00000000..1abdc68c
--- /dev/null
+++ b/site/content/xslt/functions/xpath-system-property.md
@@ -0,0 +1,121 @@
+---
+title: "system-property()"
+description: "Returns the value of a named XSLT system property such as the XSLT version, vendor name, or vendor URL."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "system-property(name)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`system-property()` returns the value of a named system property from the XSLT processor. The argument is a QName that identifies the property. Properties in the `xsl:` namespace are defined by the XSLT specification; processor vendors may expose additional properties in their own namespaces.
+
+The three standard XSLT 1.0 properties are:
+
+| Property name | Type | Description |
+|---|---|---|
+| `xsl:version` | number | The XSLT version supported by the processor (e.g. `1` or `2`). |
+| `xsl:vendor` | string | A string identifying the XSLT processor vendor. |
+| `xsl:vendor-url` | string | A URL with more information about the vendor or processor. |
+
+If an unknown property name is passed, `system-property()` returns an empty string.
+
+The function is most commonly used for version detection: testing whether the processor supports XSLT 2.0 so that the stylesheet can adapt its behaviour accordingly.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:QName | Yes | The name of the system property to retrieve. |
+
+## Return value
+
+`xs:string` or `xs:number` — the property value, or `""` for unknown properties.
+
+## Examples
+
+### Display processor information
+
+**Input XML:**
+```xml
+
+System Info
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (Saxon example):**
+```xml
+
+ 2
+ Saxonica
+ http://www.saxonica.com/
+
+```
+
+### Adapt behaviour based on XSLT version
+
+**Input XML:**
+```xml
+
+3.14159
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3.14
+
+```
+
+## Notes
+
+- `system-property('xsl:version')` returns a number, not a string. Use numeric comparison (`>= 2`) rather than string comparison (`= '2'`).
+- For unknown property names, the return value is `""` (empty string), not an error.
+- Vendor-specific properties must be referenced using a namespace prefix that maps to the vendor's extension namespace.
+- In XSLT 2.0+, the same function is available with the same three standard properties. Processors may report `xsl:version` as `2` or higher. The XSLT 3.0 specification also defines this function identically.
+
+## See also
+
+- [element-available()](../xpath-element-available)
+- [function-available()](../xpath-function-available)
diff --git a/site/content/xslt/functions/xpath-trace.md b/site/content/xslt/functions/xpath-trace.md
new file mode 100644
index 00000000..3c35f274
--- /dev/null
+++ b/site/content/xslt/functions/xpath-trace.md
@@ -0,0 +1,114 @@
+---
+title: "trace()"
+description: "Emits a trace message to the processor's trace output and returns the value unchanged; used for debugging."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "trace(value, label?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`trace()` is a debugging function that sends a labeled trace message to the processor's diagnostic output, then returns its first argument unchanged. Because it is transparent with respect to the value it passes through, `trace()` can be inserted into any XPath expression without changing the expression's semantics — only the side-effect of emitting a message is added.
+
+In XPath 2.0, the function takes two arguments: the value to trace and a string label. In XPath 3.1, the `label` argument became optional. The exact format and destination of the trace message is implementation-defined; Saxon writes to standard error with the label prepended to the value's string representation.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `value` | item()* | Yes | The value to be passed through and emitted in the trace message. |
+| `label` | xs:string | Yes in 2.0, No in 3.1 | A descriptive label prepended to the trace output. |
+
+## Return value
+
+`item()*` — the same value as `value`, returned unchanged.
+
+## Examples
+
+### Tracing a variable mid-expression
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Trace output (to stderr):**
+```
+Grand total: 425
+```
+
+**Result tree:**
+```xml
+
+ 425
+
+```
+
+### Tracing selected nodes
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Trace output:**
+```
+High-value orders: order order
+```
+
+**Result tree:**
+```xml
+
+
+
+
+```
+
+## Notes
+
+- `trace()` is purely a debugging aid; remove or comment out calls before deploying to production to avoid polluting logs.
+- Because `trace()` returns its input unchanged, it can be wrapped around any sub-expression without affecting correctness.
+- In XSLT 3.0, `xsl:message` with `select` is an alternative that allows richer formatting and is more visible in the stylesheet structure.
+- The `label` argument was made optional in XPath 3.1; in XPath 2.0 both arguments are required.
+
+## See also
+
+- [xsl:message](../xsl-message)
+- [error()](../xpath-error)
diff --git a/site/content/xslt/functions/xpath-translate.md b/site/content/xslt/functions/xpath-translate.md
new file mode 100644
index 00000000..b262105c
--- /dev/null
+++ b/site/content/xslt/functions/xpath-translate.md
@@ -0,0 +1,125 @@
+---
+title: "translate()"
+description: "Replaces characters in a string one-for-one using a from/to mapping, or removes characters that appear in 'from' but have no corresponding character in 'to'."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "string function"
+syntax: "translate(string, from, to)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`translate()` scans each character of `string` and replaces it according to a character mapping defined by `from` and `to`. For each character at position `i` in `from`, the corresponding character at position `i` in `to` is its replacement. If a character appears in `from` but `to` is shorter (i.e. there is no character at the same position in `to`), the character is **deleted** from the output.
+
+Characters not present in `from` are copied unchanged.
+
+This makes `translate()` the XPath 1.0 tool for:
+- Converting case (e.g. uppercase to lowercase) without processor extensions.
+- Removing unwanted characters (digits, punctuation, control characters).
+- Simple one-to-one character substitutions.
+
+For pattern-based replacement, use `replace()` in XSLT 2.0+.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string | Yes | The input string to transform. |
+| `from` | xs:string | Yes | Characters to match. Each character is a distinct entry in the mapping. |
+| `to` | xs:string | Yes | Replacement characters. May be shorter than `from`; missing positions mean deletion. |
+
+## Return value
+
+`xs:string` — the transformed string with characters replaced or removed.
+
+## Examples
+
+### Convert to lowercase (ASCII only)
+
+**Input XML:**
+```xml
+
+
+ HELLO WORLD
+ Mixed Case Text
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ hello world
+ mixed case text
+
+```
+
+### Remove non-numeric characters
+
+**Input XML:**
+```xml
+
+
+ (555) 123-4567
+ +1 800 555 0199
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 5551234567
+ 18005550199
+
+```
+
+## Notes
+
+- If a character appears more than once in `from`, the **first** occurrence defines the mapping; subsequent occurrences are ignored.
+- When `to` is the empty string `""`, every character in `from` is deleted from the output.
+- `translate()` operates on individual code points, not substrings. It cannot replace multi-character sequences. Use `replace()` (XSLT 2.0+) for substring replacement.
+- The ASCII case-folding technique (`translate(., 'ABC...', 'abc...')`) does not handle accented or non-Latin characters. For full Unicode case conversion in XSLT 2.0+, use `lower-case()` or `upper-case()`.
+
+## See also
+
+- [normalize-space()](../xpath-normalize-space)
+- [contains()](../xpath-contains)
+- [replace()](../xpath-replace) — requires XSLT 2.0+
diff --git a/site/content/xslt/functions/xpath-true.md b/site/content/xslt/functions/xpath-true.md
new file mode 100644
index 00000000..7b35e59b
--- /dev/null
+++ b/site/content/xslt/functions/xpath-true.md
@@ -0,0 +1,125 @@
+---
+title: "true()"
+description: "Returns the boolean value true. Used in XPath expressions and xsl:if tests where an unconditional true value is needed."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "boolean function"
+syntax: "true()"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`true()` returns the boolean literal `true`. It takes no arguments and exists because XPath 1.0 has no boolean literal syntax — unlike languages such as Java or Python, you cannot write the bare word `true` in an XPath expression and expect it to be interpreted as a boolean.
+
+The most common use is comparing attribute values that represent boolean flags (e.g. `@enabled = 'true'`), or setting a default condition in `xsl:when` using `` as a fallback branch that is always matched.
+
+`true()` is also useful when passing a boolean parameter to a template or evaluating a condition in a variable: ` `.
+
+## Parameters
+
+This function takes no parameters.
+
+## Return value
+
+`xs:boolean` — always returns `true`.
+
+## Examples
+
+### Use true() as a catch-all xsl:when branch
+
+**Input XML:**
+```xml
+
+
+ - Alpha
+ - Beta
+ - Gamma
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alpha
+ Beta
+ Gamma
+
+```
+
+### Assign a boolean variable
+
+**Input XML:**
+```xml
+
+
+ Sales Q1
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+ Report body here.
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Report body here.
+
+```
+
+## Notes
+
+- XPath 1.0 has no bare boolean literals. You must use `true()` and `false()` as function calls.
+- Using `` is a valid (though verbose) alternative to ``. Prefer `` for readability in most cases.
+- Comparing a string attribute like `@flag = 'true'` performs string comparison, not a boolean conversion. If you need the attribute value interpreted as boolean, use `boolean(@flag = 'true')` explicitly.
+- In XSLT 2.0+ you can use `xs:boolean('true')` for schema-aware processing, but `true()` remains valid.
+
+## See also
+
+- [false()](../xpath-false)
+- [boolean()](../xpath-boolean)
+- [not()](../xpath-not)
diff --git a/site/content/xslt/functions/xpath-type-available.md b/site/content/xslt/functions/xpath-type-available.md
new file mode 100644
index 00000000..85c900a1
--- /dev/null
+++ b/site/content/xslt/functions/xpath-type-available.md
@@ -0,0 +1,109 @@
+---
+title: "type-available()"
+description: "Returns true if the schema type named by the argument is available in the static context."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "type-available(type-name)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`type-available()` tests whether a named XML Schema type is known to the processor in the current static context. The argument is a string containing the lexical QName of the type, resolved against the in-scope namespace bindings. The function returns `true` if the type exists and can be used for casting, instance-of tests, or schema validation; otherwise it returns `false`.
+
+This function is used in conjunction with `xsl:if` or `xsl:when` to write portable stylesheets that adapt their behavior based on which schema types have been imported. Built-in schema types from the `xs:` namespace are always available. User-defined types from imported schemas are available only when schema-awareness is active.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `type-name` | xs:string | Yes | The lexical QName of the schema type to test, resolved in the current namespace context. |
+
+## Return value
+
+`xs:boolean` — `true` if the named type is available, `false` otherwise.
+
+## Examples
+
+### Conditional behavior based on schema type availability
+
+**Input XML:**
+```xml
+
+
+ 42
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 84
+
+```
+
+### Checking for a user-defined type
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ User-defined type is available
+
+
+ Running without schema import
+
+
+
+
+```
+
+**Output (without schema import):**
+```
+Running without schema import
+```
+
+## Notes
+
+- All types in the `xs:` namespace are available in any XSLT 2.0 or later processor that supports the XML Schema built-in types, regardless of whether any schema has been imported.
+- User-defined types must be imported with `xsl:import-schema` before they are recognized by `type-available()`.
+- `type-available()` tests availability at runtime, but type names must still be resolved at compile time using in-scope namespaces.
+- The analogous functions `function-available()` and `element-available()` test for XSLT extension functions and elements respectively.
+
+## See also
+
+- [function-available()](../xpath-function-available)
+- [element-available()](../xpath-element-available)
+- [xsl:import-schema](../xsl-import-schema)
diff --git a/site/content/xslt/functions/xpath-unordered.md b/site/content/xslt/functions/xpath-unordered.md
new file mode 100644
index 00000000..bd52286b
--- /dev/null
+++ b/site/content/xslt/functions/xpath-unordered.md
@@ -0,0 +1,115 @@
+---
+title: "unordered()"
+description: "Returns the items in the sequence in an implementation-defined order; a hint to the processor that order does not matter."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "unordered(sequence)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`unordered()` returns a sequence containing exactly the same items as its argument but in an order chosen by the processor. It is a performance hint: by calling `unordered()` you tell the processor that your code does not depend on the relative order of the items, allowing the processor to avoid sorting or impose any order that is convenient for its evaluation strategy.
+
+In practice, most processors return the items in the same order they received them, so the observable behavior is often identical to not calling `unordered()`. The benefit is theoretical and optimizer-driven. The function is the XPath counterpart to the SQL `ORDER BY`-less query hint — correct code should not depend on the actual order returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The input sequence whose order may be rearranged. |
+
+## Return value
+
+`item()*` — the same items as the input in an implementation-defined order.
+
+## Examples
+
+### Processing nodes where order is irrelevant
+
+**Input XML:**
+```xml
+
+
+ 30
+ 3
+ false
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (order may vary):**
+```xml
+
+
+
+
+
+```
+
+### Combining with distinct-values
+
+**Input XML:**
+```xml
+
+
+ xslt xpath xslt xml
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ xslt
+ xpath
+ xml
+
+```
+
+## Notes
+
+- `unordered()` is semantically a no-op in almost all real processor implementations; its value is as a documentation hint to human readers and as a signal to static analysis tools.
+- Do not rely on `unordered()` to randomize or shuffle a sequence; it does not guarantee any particular ordering different from the input.
+- Combining `unordered()` with a subsequent `sort()` or `xsl:sort` negates its purpose.
+- The function was introduced to enable future streaming or parallel evaluation strategies in conforming processors.
+
+## See also
+
+- [reverse()](../xpath-reverse)
+- [subsequence()](../xpath-subsequence)
+- [distinct-values()](../xpath-distinct-values)
diff --git a/site/content/xslt/functions/xpath-unparsed-entity-uri.md b/site/content/xslt/functions/xpath-unparsed-entity-uri.md
new file mode 100644
index 00000000..ec3a8e76
--- /dev/null
+++ b/site/content/xslt/functions/xpath-unparsed-entity-uri.md
@@ -0,0 +1,125 @@
+---
+title: "unparsed-entity-uri()"
+description: "Returns the URI of an unparsed entity declared in the DTD of the source document, given the entity's name."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "node function"
+syntax: "unparsed-entity-uri(name)"
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`unparsed-entity-uri()` retrieves the system identifier (URI) of an unparsed entity declared in the DTD of the source document. Unparsed entities are a DTD mechanism for embedding references to non-XML resources — typically binary files such as images, audio, or video — inside an XML document using `ENTITY` and `NOTATION` declarations.
+
+Given the entity name (a string), the function returns the entity's system identifier URI as declared in the DTD. If no unparsed entity with that name exists in the document's DTD, the function returns the empty string `""`.
+
+This function is rarely needed in modern XML processing. DTD-based unparsed entities have largely been superseded by direct URI references in attribute values or XLink. However, `unparsed-entity-uri()` remains the correct tool when processing legacy documents that rely on this mechanism.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:string | Yes | The name of the unparsed entity as declared in the DTD. |
+
+## Return value
+
+`xs:string` — the system identifier URI of the unparsed entity, or `""` if not found.
+
+## Examples
+
+### Retrieve an image URI from an unparsed entity
+
+**Input XML (with DTD):**
+```xml
+
+
+
+
+
+
+
+]>
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+
+
Widget
+
+
+
+
Gadget
+
+
+
+```
+
+### Guard against missing entity
+
+**Input XML (with DTD as above):**
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The function only works when the source document is accompanied by a parsed DTD that includes the relevant `ENTITY` and `NOTATION` declarations.
+- If the XML processor is not validating or has not read the DTD, unparsed entity declarations may not be available, and the function will return `""`.
+- `unparsed-entity-uri()` is scoped to the **context document** only. It looks up entities in the DTD of the document containing the context node, not the stylesheet or any other loaded document.
+- In XSLT 2.0+, the function is available as `fn:unparsed-entity-uri()` with the same semantics. A companion function `fn:unparsed-entity-public-id()` was added to retrieve the public identifier.
+- Modern XML workflows rarely use unparsed entities. For new designs, prefer storing URIs directly in attributes without DTD entity indirection.
+
+## See also
+
+- [document()](../xpath-document)
+- [id()](../xpath-id)
diff --git a/site/content/xslt/functions/xpath-unparsed-text-available.md b/site/content/xslt/functions/xpath-unparsed-text-available.md
new file mode 100644
index 00000000..886346a9
--- /dev/null
+++ b/site/content/xslt/functions/xpath-unparsed-text-available.md
@@ -0,0 +1,86 @@
+---
+title: "unparsed-text-available()"
+description: "Returns true if unparsed-text() would succeed for the given URI and encoding, allowing safe guarded file reads."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "unparsed-text-available(uri, encoding?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`unparsed-text-available()` checks whether a call to `unparsed-text()` with the same arguments would succeed. It returns `true` if the resource exists and can be read with the specified encoding, and `false` otherwise — without raising an error.
+
+Use it as a guard before calling `unparsed-text()` or `unparsed-text-lines()` when the resource may not always be present.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `uri` | xs:string? | Yes | The URI of the text resource to test. |
+| `encoding` | xs:string | No | Character encoding to test (e.g., `"UTF-8"`). |
+
+## Return value
+
+`xs:boolean` — `true` if the resource is available, `false` if it is not (or if the argument is the empty sequence).
+
+## Examples
+
+### Conditionally include a text file
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Load optional configuration files
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The function should be called with the same arguments you intend to pass to `unparsed-text()` to guarantee the guard matches.
+- Even if `unparsed-text-available()` returns `true`, the subsequent `unparsed-text()` call might still fail in rare race conditions (e.g., the file was deleted in between). This is unlikely in batch transformations.
+- Available in Saxon 9.x+ with XSLT 2.0 stylesheets; formally part of XPath 3.0.
+
+## See also
+
+- [unparsed-text()](../xpath-unparsed-text)
+- [unparsed-text-lines()](../xpath-unparsed-text-lines)
diff --git a/site/content/xslt/functions/xpath-unparsed-text-lines.md b/site/content/xslt/functions/xpath-unparsed-text-lines.md
new file mode 100644
index 00000000..58843af2
--- /dev/null
+++ b/site/content/xslt/functions/xpath-unparsed-text-lines.md
@@ -0,0 +1,90 @@
+---
+title: "unparsed-text-lines()"
+description: "Reads a text file from a URI and returns its lines as a sequence of strings, one item per line."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "unparsed-text-lines(uri, encoding?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`unparsed-text-lines()` retrieves a text resource and returns each line as a separate `xs:string` item in a sequence. Line endings (`\r\n`, `\n`, `\r`) are removed from each item. An empty trailing line produced by a final newline is not included.
+
+This is more convenient than `unparsed-text()` followed by `tokenize()` when you want to iterate over lines directly.
+
+This function is part of XPath 3.0 but is supported by Saxon 9.x+ with XSLT 2.0 stylesheets.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `uri` | xs:string? | Yes | The URI of the text resource. |
+| `encoding` | xs:string | No | Character encoding (e.g., `"UTF-8"`). |
+
+## Return value
+
+`xs:string*` — a sequence of strings, one per line, or the empty sequence if the URI argument is the empty sequence.
+
+## Examples
+
+### Parse a CSV file line by line
+
+**Stylesheet (reads data.csv):**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output (for data.csv with header + 2 rows):**
+```xml
+
+```
+
+### Count non-empty lines in a file
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Line endings are stripped from each returned string.
+- Unlike `tokenize(unparsed-text(...), '\n')`, a trailing newline does not produce a spurious empty item.
+- Use `unparsed-text-available()` first if the file may not exist.
+- Formally part of XPath 3.0; available in Saxon 9.x+ with XSLT 2.0 stylesheets.
+
+## See also
+
+- [unparsed-text()](../xpath-unparsed-text)
+- [unparsed-text-available()](../xpath-unparsed-text-available)
diff --git a/site/content/xslt/functions/xpath-unparsed-text.md b/site/content/xslt/functions/xpath-unparsed-text.md
new file mode 100644
index 00000000..e00b81ee
--- /dev/null
+++ b/site/content/xslt/functions/xpath-unparsed-text.md
@@ -0,0 +1,87 @@
+---
+title: "unparsed-text()"
+description: "Reads a plain text file from a URI and returns its contents as an xs:string, with optional encoding specification."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "unparsed-text(uri, encoding?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`unparsed-text()` retrieves the contents of a text resource at the given URI and returns it as a single `xs:string`. The resource is treated as plain text — no XML parsing is performed. This is useful for reading CSV files, plain-text templates, or any non-XML data that must be processed within an XSLT transformation.
+
+If the URI argument is the empty sequence, the empty sequence is returned. The function raises an error if the resource cannot be retrieved or decoded.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `uri` | xs:string? | Yes | The URI of the text resource. Relative URIs are resolved against the static base URI. |
+| `encoding` | xs:string | No | The character encoding to use (e.g., `"UTF-8"`, `"ISO-8859-1"`). If omitted, the encoding is determined from the resource's BOM or defaults to UTF-8. |
+
+## Return value
+
+`xs:string?` — the text content of the resource as a single string, or the empty sequence if the URI argument is the empty sequence.
+
+## Examples
+
+### Read a CSV file and split into rows
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (for a data.csv with three lines):**
+```xml
+
+ id,name,value
+ 1,alpha,100
+ 2,beta,200
+
+```
+
+### Embed a text file as a CDATA section
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Use `unparsed-text-available()` to guard against missing files without raising an error.
+- For processing line by line without constructing the full string first, use `unparsed-text-lines()`.
+- Relative URIs are resolved against the **static base URI** of the stylesheet, not the source document.
+- Line endings in the returned string are normalised to `
` by the processor.
+
+## See also
+
+- [unparsed-text-lines()](../xpath-unparsed-text-lines)
+- [unparsed-text-available()](../xpath-unparsed-text-available)
diff --git a/site/content/xslt/functions/xpath-upper-case.md b/site/content/xslt/functions/xpath-upper-case.md
new file mode 100644
index 00000000..f65d26ec
--- /dev/null
+++ b/site/content/xslt/functions/xpath-upper-case.md
@@ -0,0 +1,97 @@
+---
+title: "upper-case()"
+description: "Converts every character of a string to its Unicode uppercase equivalent using locale-independent Unicode case mapping."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "string function"
+syntax: "upper-case(string)"
+tags: ["xslt", "reference", "xslt2", "xpath"]
+---
+
+## Description
+
+`upper-case()` returns a copy of the input string with every character converted to uppercase according to Unicode case mappings. The conversion is locale-independent and uses the Unicode default case folding rules — it does not consider language-specific rules (e.g., Turkish dotless-i). For language-sensitive uppercasing, a collation-aware approach or custom extension function is needed.
+
+If the argument is an empty sequence, the function returns the empty string `""`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `string` | xs:string? | Yes | The string to convert. |
+
+## Return value
+
+`xs:string` — the input string with all characters mapped to uppercase.
+
+## Examples
+
+### Basic uppercase conversion
+
+**Input XML:**
+```xml
+
+
+ Hello, World!
+ xslt is powerful
+ Ärger mit Ü
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ HELLO, WORLD!
+ XSLT IS POWERFUL
+ ÄRGER MIT Ü
+
+```
+
+### Case-insensitive comparison
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `upper-case()` is not the same as the `i` flag on `matches()`. The function changes the string; the flag changes how matching works.
+- For true locale-aware uppercasing (e.g., Turkish `i` → `İ`), use an extension function or a collation-aware approach.
+- Numeric, punctuation, and whitespace characters are returned unchanged.
+- Combining `upper-case()` with `normalize-unicode()` can help with Unicode normalization before comparison.
+
+## See also
+
+- [lower-case()](../xpath-lower-case)
+- [normalize-unicode()](../xpath-normalize-unicode)
+- [normalize-space()](../xpath-normalize-space)
diff --git a/site/content/xslt/functions/xpath-uri-collection.md b/site/content/xslt/functions/xpath-uri-collection.md
new file mode 100644
index 00000000..3b3ed985
--- /dev/null
+++ b/site/content/xslt/functions/xpath-uri-collection.md
@@ -0,0 +1,92 @@
+---
+title: "uri-collection()"
+description: "Returns a sequence of xs:anyURI values from a named collection, giving the URIs of the contained documents."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "node function"
+syntax: "uri-collection(uri?)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`uri-collection()` returns a sequence of `xs:anyURI` values — the URIs of documents in a collection — rather than the documents themselves. It is the URI counterpart of `collection()`: instead of loading each document, it gives you the URIs so you can decide how and when to load them.
+
+This is useful when you want to inspect, filter, or log available URIs before loading, or when you want to load documents selectively.
+
+Formally part of XPath 3.0; supported by Saxon 9.x+ with XSLT 2.0 stylesheets.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `uri` | xs:string? | No | URI identifying the collection. Omit for the default collection. |
+
+## Return value
+
+`xs:anyURI*` — a sequence of URIs of the documents in the collection.
+
+## Examples
+
+### List available XML files in a directory
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (example):**
+```xml
+
+ file:///data/books/book1.xml
+ file:///data/books/book2.xml
+
+```
+
+### Selectively load large files based on URI pattern
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The URI syntax follows the same Saxon-specific conventions as `collection()`: `file:///path/?select=*.xml`.
+- `uri-collection()` does not load the documents; use `doc()` or `document()` to load them individually.
+- Formally part of XPath 3.0; available in Saxon 9.x+ with XSLT 2.0 stylesheets.
+
+## See also
+
+- [collection()](../xpath-collection)
+- [document-uri()](../xpath-document-uri)
diff --git a/site/content/xslt/functions/xpath-xml-to-json.md b/site/content/xslt/functions/xpath-xml-to-json.md
new file mode 100644
index 00000000..9e75cfb0
--- /dev/null
+++ b/site/content/xslt/functions/xpath-xml-to-json.md
@@ -0,0 +1,142 @@
+---
+title: "xml-to-json()"
+description: "Converts the W3C XML representation of JSON back to a JSON string, reversing json-to-xml()."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "JSON function"
+syntax: "xml-to-json(node, options?)"
+tags: ["xslt", "reference", "xslt3", "xpath"]
+---
+
+## Description
+
+`xml-to-json()` converts an XML node tree in the W3C JSON-to-XML format back into a JSON string. It is the inverse of `json-to-xml()`. The input must be a node (element or document node) whose structure follows the W3C mapping: ``, ``, ``, ``, ``, and `` elements in the namespace `http://www.w3.org/2005/xpath-functions`.
+
+The function is useful when you need to manipulate JSON content using standard XSLT tree-transformation techniques and then serialize the result back to JSON. The `options` map accepts an `"indent"` key (boolean) to produce pretty-printed output.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `node` | `node()?` | Yes | An element or document node in the W3C JSON-XML format. Empty input returns the empty sequence. |
+| `options` | `map(xs:string, item()*)` | No | Output options. `"indent"` (boolean, default false) produces pretty-printed JSON. |
+
+## Return value
+
+`xs:string?` — the JSON serialization of the input node tree, or empty sequence if the input is empty.
+
+## Examples
+
+### Round-tripping JSON through XML transformation
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ published
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+{"status":"published","count":3}
+```
+
+### Building a JSON response from XML data
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```json
+[
+ {
+ "id": 1,
+ "total": 99.5,
+ "currency": "EUR"
+ },
+ {
+ "id": 2,
+ "total": 149,
+ "currency": "USD"
+ }
+]
+```
+
+## Notes
+
+- The input must strictly conform to the W3C JSON-XML format. Unknown element names or missing `key` attributes on `` children will cause a dynamic error.
+- `xml-to-json()` does not accept arbitrary XML. For serializing arbitrary XML to a string, use `serialize()`.
+- Use the `"indent"` option for human-readable debugging output; omit it for compact JSON in production.
+- Number formatting follows XDM rules; trailing zeros after the decimal point may be suppressed.
+
+## See also
+
+- [json-to-xml()](../xpath-json-to-xml)
+- [serialize()](../xpath-serialize)
diff --git a/site/content/xslt/functions/xpath-year-from-date.md b/site/content/xslt/functions/xpath-year-from-date.md
new file mode 100644
index 00000000..a8e614e6
--- /dev/null
+++ b/site/content/xslt/functions/xpath-year-from-date.md
@@ -0,0 +1,96 @@
+---
+title: "year-from-date()"
+description: "Extracts the year component from an xs:date value as an xs:integer."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "date function"
+syntax: "year-from-date(date)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`year-from-date()` returns the year component of an `xs:date` value as an `xs:integer`. For proleptic Gregorian calendar dates, years before the common era are represented as non-positive integers (year 1 BCE = 0, year 2 BCE = -1, etc.).
+
+If the argument is the empty sequence, the empty sequence is returned.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `date` | xs:date? | Yes | The date value from which to extract the year. |
+
+## Return value
+
+`xs:integer?` — the year component of the date, or the empty sequence if the argument is the empty sequence.
+
+## Examples
+
+### Extract the year from date attributes
+
+**Input XML:**
+```xml
+
+
+ Learning XSLT
+ XPath in Practice
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 2020
+ 2023
+
+```
+
+### Filter items from the current year
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The argument must be typed as `xs:date`, not a plain string. Cast with `xs:date(@attr)` when reading attribute values.
+- To get the current year, use `year-from-date(current-date())`.
+- Companion functions for the other date components are `month-from-date()` and `day-from-date()`.
+- For `xs:dateTime` values, use `year-from-dateTime()` instead.
+
+## See also
+
+- [month-from-date()](../xpath-month-from-date)
+- [day-from-date()](../xpath-day-from-date)
+- [current-date()](../xpath-current-date)
diff --git a/site/content/xslt/functions/xpath-zero-or-one.md b/site/content/xslt/functions/xpath-zero-or-one.md
new file mode 100644
index 00000000..1f3e9b03
--- /dev/null
+++ b/site/content/xslt/functions/xpath-zero-or-one.md
@@ -0,0 +1,110 @@
+---
+title: "zero-or-one()"
+description: "Asserts that the sequence contains zero or one items; raises a dynamic error if it contains more than one item."
+date: 2026-04-19T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "sequence function"
+syntax: "zero-or-one(sequence)"
+tags: ["xslt", "reference", "xpath", "xslt2"]
+---
+
+## Description
+
+`zero-or-one()` is a cardinality assertion function. It returns the sequence unchanged when it contains zero or one items, and raises a dynamic error (`FORG0003`) if the sequence contains two or more items. The function is the XPath equivalent of an optional element that must not appear more than once.
+
+This function is useful when you need to assign a node to a variable and want to assert that the source never unexpectedly produces multiple matches. It is also the standard way to annotate the return type of a function that may produce an optional result.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `sequence` | item()* | Yes | The sequence that must contain zero or one items. |
+
+## Return value
+
+`item()?` — the original sequence (empty or a single item). Raises `FORG0003` if the sequence contains more than one item.
+
+## Examples
+
+### Optional element lookup
+
+**Input XML:**
+```xml
+
+
+ Alice
+ Al
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+ (
+
+ )
+
+
+
+
+```
+
+**Output:**
+```xml
+Alice (Al)
+```
+
+### Detecting accidental duplicates
+
+**Input XML:**
+```xml
+
+
+ First
+ Second
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (error raised):**
+```
+FORG0003: zero-or-one() called with a sequence containing more than one item
+```
+
+## Notes
+
+- The error code raised is `err:FORG0003`.
+- In XSLT 2.0 function signatures, a parameter typed as `item()?` implicitly accepts zero or one items; `zero-or-one()` enforces this same constraint in XPath expressions.
+- Unlike `exactly-one()`, this function permits an empty sequence, making it suitable for optional elements or attributes.
+- When the goal is simply to take the first item without asserting uniqueness, use `($seq)[1]` instead.
+
+## See also
+
+- [exactly-one()](../xpath-exactly-one)
+- [one-or-more()](../xpath-one-or-more)
+- [empty()](../xpath-empty)
+- [error()](../xpath-error)
diff --git a/site/content/xslt/functions/xsl-accept.md b/site/content/xslt/functions/xsl-accept.md
new file mode 100644
index 00000000..e8018a42
--- /dev/null
+++ b/site/content/xslt/functions/xsl-accept.md
@@ -0,0 +1,111 @@
+---
+title: "xsl:accept"
+description: "Inside xsl:use-package, accepts specific components from the used package and optionally restricts their visibility."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:accept` appears as a child of `xsl:use-package` and controls which components from the used package are imported into the current package or stylesheet, and with what visibility. It mirrors `xsl:expose` from the producer side: where `xsl:expose` declares what a package offers, `xsl:accept` declares what a consumer is willing to receive.
+
+You can use `xsl:accept` to hide components that the used package exposes publicly—for example, to prevent an internal utility function from accidentally leaking into downstream consumers. You can also use it to document intent, making it explicit which components the current stylesheet depends on. Components accepted with `visibility="hidden"` become completely invisible outside the current package.
+
+When `xsl:use-package` has no `xsl:accept` children, all public and final components of the used package are automatically available. As soon as one `xsl:accept` is present, only the matched and accepted components are available; others are treated as if not imported.
+
+## Parameters
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `component` | token | Yes | Type of component: `function`, `template`, `variable`, `attribute-set`, `type`, or `mode`. |
+| `match` | pattern | Yes | A name pattern selecting which components of the given type to accept. |
+| `visibility` | token | Yes | The visibility to assign in this consuming context: `public`, `final`, `private`, or `hidden`. |
+
+## Return value
+
+`xsl:accept` is a declaration; it produces no XDM value.
+
+## Examples
+
+### Accepting only specific functions from a utility package
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Input XML:**
+```xml
+
+
+ introduction to xslt
+ advanced techniques
+
+```
+
+**Output:**
+```xml
+
+ Introduction To Xslt
+ Advanced Techniques
+
+```
+
+### Hiding internal components while re-exporting selected ones
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:accept` can only reduce visibility, not increase it. A component marked `final` by its package cannot be accepted as `public` (overridable).
+- When multiple `xsl:accept` declarations match the same component, the most specific match wins, with more specific names taking priority over wildcards.
+- If a used package contains `abstract` components that are not overridden via `xsl:override`, a static error is raised even if the abstract component is hidden with `xsl:accept`.
+- Omitting `xsl:accept` entirely is equivalent to accepting all public and final components with their original visibility unchanged.
+
+## See also
+
+- [xsl:use-package](../xsl-use-package)
+- [xsl:expose](../xsl-expose)
+- [xsl:override](../xsl-override)
diff --git a/site/content/xslt/functions/xsl-accumulator-rule.md b/site/content/xslt/functions/xsl-accumulator-rule.md
new file mode 100644
index 00000000..56845e28
--- /dev/null
+++ b/site/content/xslt/functions/xsl-accumulator-rule.md
@@ -0,0 +1,124 @@
+---
+title: "xsl:accumulator-rule"
+description: "Defines when and how an xsl:accumulator's value is updated, matching nodes by pattern and firing at the start or end of matched elements."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:accumulator-rule` specifies the update logic for an `xsl:accumulator`. Each rule has a `match` pattern (identical in syntax to the `match` attribute of `xsl:template`) and a `phase` that determines whether it fires when the processor enters (`start`) or exits (`end`) a matched element.
+
+When a rule fires, the body expression (either the `select` attribute or the sequence constructor content) is evaluated and its result becomes the new accumulator value. Inside the rule, the special variable `$value` holds the *current* accumulator value before this rule fires. This lets you write incremental updates: `select="$value + xs:decimal(@amount)"` adds the current node's amount to the running total.
+
+Rules within one accumulator are evaluated in document order; if multiple rules could match the same node (due to broad patterns), all matching rules fire in specificity order, similar to template priority. The most specific match wins, just as with `xsl:template`.
+
+The `phase` attribute is optional for non-element nodes: attributes, text nodes, comments, and processing instructions cannot have a start/end phase distinction, so `phase` defaults to `end` for them. For element nodes, `start` fires before any descendants are processed; `end` fires after all descendants have been processed.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `match` | pattern | Yes | Pattern identifying the nodes that trigger this rule. |
+| `phase` | `start\|end` | No | When to fire for element nodes: `start` (on entry) or `end` (on exit). Default `end`. |
+| `select` | expression | No | The new accumulator value. Mutually exclusive with content. Variable `$value` is in scope. |
+
+## Examples
+
+### Tracking nested depth with start and end rules
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+
+```
+
+### Accumulating a list of all ancestor titles
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+```
+
+## Notes
+
+- The `$value` variable is always available inside an `xsl:accumulator-rule` and refers to the current accumulator value before this rule fires.
+- For `phase="start"`, `$value` is the accumulator value before the element's opening tag was reached.
+- For `phase="end"`, `$value` includes all updates made by descendants of the current element.
+- Rules with equal priority for the same node follow the same conflict-resolution logic as `xsl:template`.
+
+## See also
+
+- [xsl:accumulator](../xsl-accumulator)
+- [xsl:use-accumulators](../xsl-use-accumulators)
+- [accumulator-before()](../xpath-accumulator-before)
+- [accumulator-after()](../xpath-accumulator-after)
diff --git a/site/content/xslt/functions/xsl-accumulator.md b/site/content/xslt/functions/xsl-accumulator.md
new file mode 100644
index 00000000..a3e44884
--- /dev/null
+++ b/site/content/xslt/functions/xsl-accumulator.md
@@ -0,0 +1,133 @@
+---
+title: "xsl:accumulator"
+description: "Declares a streaming accumulator that maintains a typed value updated by rules as nodes are processed, enabling stateful aggregation without multiple passes."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:accumulator` solves one of the hardest problems in streaming XSLT: maintaining state as nodes flow past the processor. In a non-streaming stylesheet you can freely look up ancestors, siblings, and preceding elements. In streaming mode, once a node has been processed it is gone. Accumulators bridge this gap by keeping a running value that is updated automatically as the processor enters and exits matched nodes.
+
+An accumulator is declared as a top-level element with a `name`, an XPath `as` type, and an `initial-value`. One or more `xsl:accumulator-rule` children define the update logic for specific node patterns. Rules fire in document order: a `phase="start"` rule fires when the processor encounters the opening tag; `phase="end"` fires when the closing tag is reached.
+
+To read an accumulator's value at any point, use the XPath functions `accumulator-before('name')` (the value before the current node was processed) or `accumulator-after('name')` (the value after the current node and all its descendants were processed).
+
+Accumulators must be declared in scope for any mode that uses them via `xsl:use-accumulators` on the mode or `use-accumulators` on `xsl:stream`. They are essentially a functional equivalent of mutable global state, but safe for streaming because the processor manages the update lifecycle.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | The accumulator name, used in `accumulator-before()` and `accumulator-after()`. |
+| `as` | sequence type | No | Type of the accumulated value. Default `item()*`. |
+| `initial-value` | expression | Yes | Starting value before any node is processed. |
+| `streamable` | `yes\|no` | No | Whether the accumulator rules must be streamable. Default `no`. |
+
+## Examples
+
+### Tracking the current section heading while streaming
+
+**Input XML:**
+```xml
+
+
+
+ First paragraph.
+ Second paragraph.
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - First paragraph.
+ - Second paragraph.
+ - Third paragraph.
+
+```
+
+### Running total accumulator
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The variable `$value` inside `xsl:accumulator-rule` refers to the *current* accumulator value before the rule fires.
+- Accumulators are scoped to the document being processed. When you call `doc()`, the accumulator is re-initialised for that document.
+- Multiple accumulators can be active simultaneously on the same mode.
+- `streamable="yes"` requires each rule's `select` to be a streamable expression.
+
+## See also
+
+- [xsl:accumulator-rule](../xsl-accumulator-rule)
+- [xsl:use-accumulators](../xsl-use-accumulators)
+- [accumulator-before()](../xpath-accumulator-before)
+- [accumulator-after()](../xpath-accumulator-after)
diff --git a/site/content/xslt/functions/xsl-analyze-string.md b/site/content/xslt/functions/xsl-analyze-string.md
new file mode 100644
index 00000000..ddd57c8e
--- /dev/null
+++ b/site/content/xslt/functions/xsl-analyze-string.md
@@ -0,0 +1,139 @@
+---
+title: "xsl:analyze-string"
+description: "Processes a string against a regular expression, separating matching and non-matching substrings for independent handling."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:analyze-string` scans a string for all occurrences of a regular expression and divides the string into alternating matching and non-matching substrings. For each portion, it invokes the appropriate child element:
+
+- `xsl:matching-substring` — processes each matched portion.
+- `xsl:non-matching-substring` — processes each unmatched portion between matches.
+
+Inside `xsl:matching-substring`, the `regex-group()` function returns captured groups from the match. The instruction processes the full string from left to right, emitting output for every segment in order.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | XPath expression | Yes | The string to analyze. |
+| `regex` | xs:string (AVT) | Yes | The regular expression pattern. |
+| `flags` | xs:string (AVT) | No | Flag characters: `i` (case-insensitive), `m` (multiline), `s` (dot-all), `x` (extended). |
+
+Child elements (at least one is required):
+
+| Child | Description |
+|-------|-------------|
+| `xsl:matching-substring` | Template for matched portions. |
+| `xsl:non-matching-substring` | Template for non-matched portions. |
+| `xsl:fallback` | Fallback for processors that do not support the instruction. |
+
+## Return value
+
+A sequence of nodes and/or atomic values produced by the child templates, one per substring segment.
+
+## Examples
+
+### Marking up URLs in plain text
+
+**Input XML:**
+```xml
+
+
+ Visit https://example.com for details or http://docs.example.org/api.
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+```
+
+### Parsing dates with capture groups
+
+**Input XML:**
+```xml
+
+
+ Conference on 2026-04-18 in Berlin
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+```
+
+## Notes
+
+- Inside attribute value templates, curly braces in the `regex` must be doubled: `\d{{4}}` to match `\d{4}`.
+- Both `xsl:matching-substring` and `xsl:non-matching-substring` are optional. Omitting one effectively discards those segments.
+- `regex-group(0)` returns the entire matched string; `regex-group(n)` returns the *n*th capture group.
+- The instruction iterates all non-overlapping matches from left to right. If no match is found, the entire string is processed as a single non-matching substring.
+- XPath regex syntax is used (XML Schema flavor), which does not support lookahead or backreferences.
+
+## See also
+
+- [xsl:matching-substring](../xsl-matching-substring)
+- [xsl:non-matching-substring](../xsl-non-matching-substring)
+- [regex-group()](../xpath-regex-group)
+- [matches()](../xpath-matches)
+- [replace()](../xpath-replace)
diff --git a/site/content/xslt/functions/xsl-apply-templates.md b/site/content/xslt/functions/xsl-apply-templates.md
new file mode 100644
index 00000000..2a139807
--- /dev/null
+++ b/site/content/xslt/functions/xsl-apply-templates.md
@@ -0,0 +1,151 @@
+---
+title: "xsl:apply-templates"
+description: "Selects a set of nodes and applies the best-matching template rule to each one, enabling recursive tree processing."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:apply-templates` is the instruction that drives pattern-matching in XSLT. It selects a set of nodes (defaulting to all child nodes of the current node) and, for each selected node in turn, finds and instantiates the best-matching `xsl:template` rule. This is what makes XSLT processing recursive and tree-oriented.
+
+Unlike `xsl:for-each`, which forces a fixed sequence of instructions, `xsl:apply-templates` delegates logic to templates declared elsewhere in the stylesheet (or imported stylesheets). This separation of concerns is the idiomatic XSLT approach: the calling template does not need to know how individual nodes are transformed.
+
+The optional `mode` attribute restricts which template rules are candidates. Only templates with a matching `mode` value will fire. This allows the same source nodes to be processed differently in different phases of the transformation — for instance, building a table of contents in one mode and body content in another.
+
+Child `xsl:sort` elements placed immediately inside `xsl:apply-templates` control the order in which selected nodes are processed without modifying the source tree.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | XPath expression | No | Nodes to process. Defaults to all child nodes (`node()`). |
+| `mode` | QName | No | Restricts matching to templates with this mode. |
+
+## Examples
+
+### Basic recursive processing
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Soup
+ Salad
+
+
+ Steak
+ Pasta
+
+
+```
+
+### Using mode to process nodes twice
+
+**Input XML:**
+```xml
+
+
+ Introduction
+ Core Concepts
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Introduction
+ Core Concepts
+
+
+
+
+
+
+```
+
+## Notes
+
+- If no `select` is given, `xsl:apply-templates` processes all child nodes of the current node in document order, including text nodes. This can produce unexpected whitespace output; explicitly select `select="*"` to limit to element children only.
+- When a selected node matches no template rule, the built-in default template fires: for element nodes it recursively applies templates to children; for text nodes it copies the text value.
+- `xsl:sort` children must appear before any `xsl:with-param` children.
+- Parameters can be passed to templates via child `xsl:with-param` elements; the receiving template must declare corresponding `xsl:param` elements to access them.
+
+## See also
+
+- [xsl:template](../xsl-template)
+- [xsl:call-template](../xsl-call-template)
+- [xsl:with-param](../xsl-with-param)
+- [xsl:sort](../xsl-sort)
+- [xsl:for-each](../xsl-for-each)
diff --git a/site/content/xslt/functions/xsl-array-member.md b/site/content/xslt/functions/xsl-array-member.md
new file mode 100644
index 00000000..2e68c326
--- /dev/null
+++ b/site/content/xslt/functions/xsl-array-member.md
@@ -0,0 +1,113 @@
+---
+title: "xsl:array-member"
+description: "Defines a single member inside an xsl:array; the member value is any XDM sequence, including nested arrays, maps, or empty sequences."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:array-member` contributes one positional slot to the enclosing `xsl:array`. The value of the member is provided either through the `select` attribute (an XPath expression) or through a sequence constructor in the element content.
+
+The key distinction of `xsl:array-member` is that its value is a *sequence* — not necessarily a single item. A member can be the empty sequence `()`, a single integer, a sequence of strings, or even a nested map or array. This capability is what makes XDM arrays different from flat XPath sequences: arrays can contain heterogeneous multi-value slots.
+
+When using `select`, the expression is evaluated and the resulting sequence becomes the member. When using content, the sequence constructor result becomes the member. You cannot use both `select` and content simultaneously.
+
+In loops (`xsl:for-each`), each iteration of the loop body that contains an `xsl:array-member` adds one member to the enclosing array. This lets you build arrays of arbitrary length from input data.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | expression | No | XPath expression whose result becomes the member value. Mutually exclusive with content. |
+
+## Examples
+
+### Building a JSON array with mixed types
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (JSON):**
+```json
+[
+ {"name": "response_time", "value": 142},
+ {"name": "error_rate", "value": 0.03},
+ {"name": "uptime", "value": 99.9}
+]
+```
+
+### Array of sequences demonstrating multi-value members
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:array-member` must appear inside `xsl:array` (directly or via instructions that produce array members).
+- An `xsl:array-member` with an empty sequence value creates a slot containing `()`, which is distinct from the slot not existing.
+- Using `select="()"` explicitly creates an empty-sequence member, valid in XDM.
+- In JSON output mode, an array member that is the empty sequence is serialised as `null`.
+
+## See also
+
+- [xsl:array](../xsl-array)
+- [array:get()](../xpath-array-get)
diff --git a/site/content/xslt/functions/xsl-array.md b/site/content/xslt/functions/xsl-array.md
new file mode 100644
index 00000000..05213fda
--- /dev/null
+++ b/site/content/xslt/functions/xsl-array.md
@@ -0,0 +1,115 @@
+---
+title: "xsl:array"
+description: "Creates an XDM array from xsl:array-member children, providing ordered positional access to sequences of arbitrary XDM values in XSLT 3.0."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: " "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:array` is the instruction for constructing an XDM array. Arrays are ordered, positionally indexed collections introduced in XDM 3.1. They differ from sequences in a critical way: each member of an array can itself be a sequence of zero or more items, whereas sequences are always flat. This makes arrays essential for representing JSON arrays (which can contain nested arrays and objects) and for passing multi-valued parameters to functions.
+
+The instruction form `xsl:array` is used when the members must be computed dynamically. You populate it with `xsl:array-member` children, optionally interspersed with `xsl:for-each`, `xsl:if`, and other XSLT instructions. For simple cases where members are known at compile time, the XPath square-bracket syntax `[item1, item2]` is more concise.
+
+An XDM array is a function from an integer position (1-based) to its member value. You access members with `array:get($arr, $pos)` or the shorthand `$arr($pos)`.
+
+## Attributes
+
+`xsl:array` has no element-specific attributes. Its content must consist of `xsl:array-member` instructions (and other instructions producing array members).
+
+## Examples
+
+### Creating an array from XML nodes
+
+**Input XML:**
+```xml
+
+
+ Shape of You
+ Blinding Lights
+ Levitating
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (JSON):**
+```json
+{
+ "title": "My Playlist",
+ "tracks": ["Shape of You", "Blinding Lights", "Levitating"]
+}
+```
+
+### Array of sequences (each member holds multiple values)
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+```
+
+**Output:**
+```xml
+
+ | 5 |
+
+```
+
+## Notes
+
+- Arrays are 1-indexed. `array:get($arr, 1)` retrieves the first member.
+- Each member of an `xsl:array` is a *sequence*, not just a single item. This is what distinguishes arrays from flat sequences.
+- The XPath shorthand `[ ]` creates an array where each member is a single item.
+- To append or modify an array, use functions like `array:append()`, `array:put()`, or `array:insert-before()`.
+- `xsl:array` can be used inside `xsl:map-entry` to create JSON-compatible nested structures.
+
+## See also
+
+- [xsl:array-member](../xsl-array-member)
+- [array:get()](../xpath-array-get)
+- [xsl:map](../xsl-map)
diff --git a/site/content/xslt/functions/xsl-attribute-set.md b/site/content/xslt/functions/xsl-attribute-set.md
new file mode 100644
index 00000000..ec5b7ed2
--- /dev/null
+++ b/site/content/xslt/functions/xsl-attribute-set.md
@@ -0,0 +1,140 @@
+---
+title: "xsl:attribute-set"
+description: "Defines a named, reusable collection of attributes that can be applied to multiple elements via use-attribute-sets."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:attribute-set` is a top-level declaration that groups a set of `xsl:attribute` children under a single name. Once defined, the set can be applied to any literal result element or `xsl:element` / `xsl:copy` instruction using the `use-attribute-sets` attribute, which expands all the attributes in the set onto that element.
+
+Attribute sets promote consistency across a stylesheet. If the same combination of attributes — such as a standard HTML link appearance, a set of XML metadata attributes, or table cell formatting — is used in many places, defining it once in an attribute set avoids repetition and makes changes straightforward.
+
+Attribute sets can compose: an `xsl:attribute-set` declaration may itself reference other attribute sets via `use-attribute-sets`. When both a set's attribute and a locally written attribute share the same name, the local attribute wins.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | The name of the attribute set, referenced in `use-attribute-sets`. |
+| `use-attribute-sets` | whitespace-separated QNames | No | Other attribute sets to include (inheritance / composition). |
+
+## Examples
+
+### Shared table cell attributes
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+ 1
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Name
+ Value
+
+
+ Alpha
+ 1
+
+
+```
+
+### Composed attribute sets
+
+**Input XML:**
+```xml
+
+Text
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+ block
+ en
+
+
+
+ paragraph
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Text
+
+```
+
+## Notes
+
+- When two attribute sets define the same attribute name, the one listed later in `use-attribute-sets` takes precedence over earlier ones.
+- A local `xsl:attribute` or inline attribute on the result element overrides any attribute set attribute with the same name.
+- Circular attribute set references (set A including set B which includes set A) are an error.
+- Attribute sets are only applicable to element nodes. They cannot be used with text, comment, or processing-instruction output instructions.
+
+## See also
+
+- [xsl:attribute](../xsl-attribute)
+- [xsl:element](../xsl-element)
+- [xsl:copy](../xsl-copy)
diff --git a/site/content/xslt/functions/xsl-attribute.md b/site/content/xslt/functions/xsl-attribute.md
new file mode 100644
index 00000000..342d8d2a
--- /dev/null
+++ b/site/content/xslt/functions/xsl-attribute.md
@@ -0,0 +1,117 @@
+---
+title: "xsl:attribute"
+description: "Creates an attribute on the nearest ancestor result element, with a name and value computed at transformation time."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:attribute` adds an attribute to the result element currently being constructed. Its `name` is an attribute value template, so the attribute name can be computed from source data or variables. The attribute value is provided by the content of the `xsl:attribute` element, which may include `xsl:value-of`, `xsl:text`, and any other value-producing instructions.
+
+The common use case is adding attributes whose names or values depend on the source document. For attributes whose names and values are both static, you write them directly on literal result elements in the stylesheet (e.g., ` `) which is more concise.
+
+`xsl:attribute` must be placed before any child elements or text nodes of the target element. Once character data or child elements have been written to the output element, adding attributes raises an error.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | AVT (QName) | Yes | Attribute name, evaluated as an attribute value template. |
+| `namespace` | AVT (URI) | No | Namespace URI for the attribute. Overrides any prefix in `name`. |
+
+## Examples
+
+### Dynamic attribute name and value
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+```
+
+### Conditional attribute
+
+**Input XML:**
+```xml
+
+
+ Example
+ About
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _blank
+ noopener noreferrer
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Example
+ About
+
+```
+
+## Notes
+
+- An `xsl:attribute` that follows child element output on the same parent raises a fatal error. Always emit attributes before any child element or text content.
+- If two `xsl:attribute` instructions in the same template write to the same attribute name, the last one wins — the earlier value is silently replaced.
+- To add the same set of attributes to multiple elements, define an `xsl:attribute-set` and reference it with `use-attribute-sets`.
+- The attribute value template shorthand (`name="{expression}"`) on literal result elements is equivalent to `xsl:attribute` with `select` for simple cases and is preferred for readability.
+
+## See also
+
+- [xsl:attribute-set](../xsl-attribute-set)
+- [xsl:element](../xsl-element)
+- [xsl:copy](../xsl-copy)
diff --git a/site/content/xslt/functions/xsl-break.md b/site/content/xslt/functions/xsl-break.md
new file mode 100644
index 00000000..11119e92
--- /dev/null
+++ b/site/content/xslt/functions/xsl-break.md
@@ -0,0 +1,124 @@
+---
+title: "xsl:break"
+description: "Exits an xsl:iterate loop early and returns an optional final value, enabling efficient early-termination patterns over large sequences."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:break` terminates an `xsl:iterate` loop before the sequence is exhausted. When a `break` fires, the iteration stops immediately and the value supplied in the `select` attribute (or the content sequence constructor) becomes the result of the entire `xsl:iterate` expression. If no `select` or content is given, the result is the empty sequence.
+
+This enables patterns like "find the first matching item", "accumulate a running total until a threshold is crossed", or "process records until a sentinel value is found" — all without pre-filtering the input or using a recursive named template.
+
+`xsl:break` must appear inside `xsl:iterate`. It can be conditionally executed inside `xsl:if` or `xsl:choose`. Any `xsl:on-completion` block in the same `xsl:iterate` is skipped when a break occurs.
+
+The `select` expression (or content) that provides the break value is evaluated in the context of the current iteration, after the current iteration's body has partially executed up to the `xsl:break` instruction. Parameters updated by `xsl:next-iteration` before the break instruction are visible in the select expression.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | expression | No | The value to return as the result of the `xsl:iterate`. If absent, the content sequence constructor is used. |
+
+## Examples
+
+### Finding the first record above a threshold
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No alert threshold exceeded.
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ C
+ 103
+
+```
+
+### Accumulating a running total until a budget is exhausted
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:break` may only appear inside `xsl:iterate`. Using it elsewhere is a static error.
+- When `xsl:break` fires, any `xsl:on-completion` in the same `xsl:iterate` is **not** executed.
+- The result of the `xsl:iterate` expression is whatever `xsl:break` returns, or the result of `xsl:on-completion` if the loop completes naturally.
+- Inside streaming mode, `xsl:break` is allowed if the `xsl:iterate` is otherwise streamable.
+
+## See also
+
+- [xsl:next-iteration](../xsl-next-iteration)
+- [xsl:iterate](../xsl-iterate)
diff --git a/site/content/xslt/functions/xsl-call-template.md b/site/content/xslt/functions/xsl-call-template.md
new file mode 100644
index 00000000..097971e2
--- /dev/null
+++ b/site/content/xslt/functions/xsl-call-template.md
@@ -0,0 +1,131 @@
+---
+title: "xsl:call-template"
+description: "Invokes a named template by name, optionally passing parameters, without changing the current context node."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:call-template` invokes a template that was declared with the `name` attribute on `xsl:template`. Unlike `xsl:apply-templates`, which selects nodes and fires matching rules, `xsl:call-template` is a direct, unconditional call — similar to a function call in a procedural language. The context node, position, and size remain exactly what they were in the calling template; the named template operates in that same context.
+
+Named templates serve as reusable subroutines in XSLT. Because XSLT variables are immutable, the primary technique for producing loops or accumulations is recursive named-template calls, where each invocation passes updated values via `xsl:with-param`.
+
+Parameters are passed via child `xsl:with-param` elements. Inside the named template, `xsl:param` elements declare the expected parameters and provide default values. If a `with-param` element supplies a value, it overrides the default.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | The name of the template to call. Must match the `name` attribute of an `xsl:template` in scope. |
+
+## Examples
+
+### Reusable formatting template
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+ $
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alpha $1,200.00
+ Beta $450.00
+ Gamma $89.00
+
+```
+
+### Recursive call for string padding
+
+**Input XML:**
+```xml
+
+Warning
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+Warning.............
+```
+
+## Notes
+
+- The named template must be resolvable at compile time; forward references are allowed — template order in the file does not matter.
+- The context node inside the called template is the same as in the caller. Use `xsl:with-param` to pass node-set context explicitly if needed.
+- A named template can also have a `match` attribute, making it both callable by name and matchable by pattern.
+- Recursive calls are the standard XSLT 1.0 technique for iteration, but deep recursion can overflow the processor's stack. For large counts, consider chunk-based recursion strategies.
+
+## See also
+
+- [xsl:template](../xsl-template)
+- [xsl:apply-templates](../xsl-apply-templates)
+- [xsl:with-param](../xsl-with-param)
+- [xsl:param](../xsl-param)
diff --git a/site/content/xslt/functions/xsl-catch.md b/site/content/xslt/functions/xsl-catch.md
new file mode 100644
index 00000000..812e82d8
--- /dev/null
+++ b/site/content/xslt/functions/xsl-catch.md
@@ -0,0 +1,134 @@
+---
+title: "xsl:catch"
+description: "Handles dynamic errors thrown inside an xsl:try block, with access to error code, description, and value for precise recovery logic."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: '... '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:catch` is the error-handler sibling of `xsl:try`. When a dynamic error occurs inside the try boundary, the processor evaluates the first `xsl:catch` whose `errors` pattern matches the error code. If no `errors` attribute is present, the catch block matches all errors — equivalent to a catch-all.
+
+Inside an `xsl:catch` block, six special variables are automatically in scope, all in the `http://www.w3.org/2005/xqt-errors` namespace (conventionally bound to the prefix `err:`):
+
+- `$err:code` — the QName of the error (e.g. `err:FODT0001`).
+- `$err:description` — a human-readable string describing the error.
+- `$err:value` — the value associated with the error, if any; otherwise the empty sequence.
+- `$err:module` — the URI of the stylesheet module where the error occurred.
+- `$err:line-number` — the line number, as an `xs:integer`, if available.
+- `$err:column-number` — the column number, if available.
+
+You can use these to log structured diagnostics, branch on specific error codes, or re-raise the error using `error($err:code, $err:description, $err:value)`.
+
+Multiple `xsl:catch` elements may follow a single `xsl:try`; the processor uses the first that matches. A catch-all `xsl:catch` (no `errors` attribute) should therefore be placed last.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `errors` | error-name-list | No | Space-separated list of error QNames or namespace wildcards (e.g. `Q{http://www.w3.org/2005/xqt-errors}*`). Omit to catch all errors. |
+
+## Examples
+
+### Multiple catch blocks with error-specific handling
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Division by zero
+
+
+ Type error:
+
+
+
+ Unexpected error:
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Division by zero
+ Type error: Invalid integer value 'hello'
+ 5
+
+```
+
+### Logging errors to the output
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:catch` must be a direct child of `xsl:try`. It cannot appear standalone.
+- The `errors` attribute accepts namespace wildcards using the `Q{uri}*` syntax to catch all errors in a namespace.
+- Re-raising an error: use `error($err:code, $err:description, $err:value)` inside the catch block.
+- The error variables are only in scope within the `xsl:catch` content, not in `xsl:try` or other siblings.
+
+## See also
+
+- [xsl:try](../xsl-try)
diff --git a/site/content/xslt/functions/xsl-character-map.md b/site/content/xslt/functions/xsl-character-map.md
new file mode 100644
index 00000000..91062a67
--- /dev/null
+++ b/site/content/xslt/functions/xsl-character-map.md
@@ -0,0 +1,115 @@
+---
+title: "xsl:character-map"
+description: "Declares a named mapping of individual characters to output strings, applied during serialization to replace characters in the result."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:character-map` is a top-level declaration that defines a set of character substitutions applied during output serialization. Each substitution is specified by a child `xsl:output-character` element. When the serializer writes a character that appears in the map, it writes the mapped string instead — bypassing normal XML escaping rules.
+
+This is essential for generating output that requires non-XML escape sequences, such as HTML entities (` `, `©`), or for controlling how special characters appear in text or HTML output.
+
+The map is activated by naming it in the `use-character-maps` attribute of `xsl:output` or `xsl:result-document`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | The name of the character map, referenced from `xsl:output`. |
+| `use-character-maps` | QNames (space-separated) | No | Names of other character maps to include (compose maps). |
+
+Child elements:
+
+| Child | Description |
+|-------|-------------|
+| `xsl:output-character` | One or more character-to-string mappings. |
+
+## Return value
+
+No direct output. The map is applied by the serializer when activated via `use-character-maps`.
+
+## Examples
+
+### Outputting named HTML entities
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ © 2026
+ “ ”
+
+
+
+
+```
+
+**Output (raw HTML):**
+```html
+
+
+ My Page © 2026
+ “Some content here”
+
+
+```
+
+### Composing character maps
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2 × 3 ≤ 10
+
+
+```
+
+**Output:** `2×3≤10
`
+
+## Notes
+
+- Character maps are applied **after** serialization escaping. The mapped string is written literally — the serializer does not re-escape it.
+- Each character may appear in at most one active character map. If a character appears in multiple composed maps, behavior is processor-defined.
+- Character maps do not affect text inside CDATA sections.
+- They are a serialization feature — they have no effect on the XDM result tree inside the stylesheet; only on the final text output.
+
+## See also
+
+- [xsl:output-character](../xsl-output-character)
+- [xsl:output](../xsl-output)
+- [xsl:result-document](../xsl-result-document)
diff --git a/site/content/xslt/functions/xsl-choose.md b/site/content/xslt/functions/xsl-choose.md
new file mode 100644
index 00000000..89df399d
--- /dev/null
+++ b/site/content/xslt/functions/xsl-choose.md
@@ -0,0 +1,134 @@
+---
+title: "xsl:choose"
+description: "Multi-branch conditional that evaluates xsl:when conditions in order and optionally falls back to xsl:otherwise."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:choose` provides a switch-like construct for selecting one branch of output from several alternatives. It must contain one or more `xsl:when` children (each with its own `test` expression) and may optionally end with a single `xsl:otherwise` child as the default branch.
+
+The processor evaluates each `xsl:when` test in document order and instantiates the first one whose expression evaluates to true, then skips the rest. If no `xsl:when` matches and an `xsl:otherwise` is present, that branch is used. If no branch matches and there is no `xsl:otherwise`, nothing is output.
+
+`xsl:choose` is the XSLT equivalent of an if / else-if / else chain. Unlike chained `xsl:if` elements — which are all evaluated independently — only one branch of `xsl:choose` can ever produce output for a given node.
+
+## Attributes
+
+`xsl:choose` itself takes no attributes. Conditions are specified on the `xsl:when` children.
+
+## Examples
+
+### Classifying numeric values
+
+**Input XML:**
+```xml
+
+
+ 92
+ 73
+ 55
+ 38
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+ B
+ C
+ F
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ A
+ B
+ C
+ F
+
+```
+
+### Choosing output format based on attribute
+
+**Input XML:**
+```xml
+
+
+ - Visit site
+ - Logo
+ - Plain description
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Visit site
+
+ Plain description
+
+```
+
+## Notes
+
+- `xsl:when` elements are evaluated strictly in order; only the first matching branch fires. This matters when conditions overlap.
+- An `xsl:otherwise` without any `xsl:when` is a schema error. At least one `xsl:when` must be present.
+- `xsl:otherwise` must be the last child of `xsl:choose`; placing it before any `xsl:when` is an error.
+- `xsl:choose` can be nested to arbitrary depth, enabling complex decision trees.
+
+## See also
+
+- [xsl:when](../xsl-when)
+- [xsl:otherwise](../xsl-otherwise)
+- [xsl:if](../xsl-if)
diff --git a/site/content/xslt/functions/xsl-comment.md b/site/content/xslt/functions/xsl-comment.md
new file mode 100644
index 00000000..8c00c252
--- /dev/null
+++ b/site/content/xslt/functions/xsl-comment.md
@@ -0,0 +1,104 @@
+---
+title: "xsl:comment"
+description: "Generates an XML comment node in the result tree with content computed from the element body."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:comment` inserts an XML comment (``) into the result tree. The content of the generated comment is the string value produced by instantiating the element body, which may include `xsl:value-of` and `xsl:text` instructions as well as literal text.
+
+Comments are primarily used in HTML/XML output for debugging information, conditional comments (legacy IE technique), or generator attribution lines. They are preserved in the output document and visible to anyone reading the raw markup.
+
+`xsl:comment` takes no attributes. The text produced by its content must not contain the sequence `--` (two hyphens), as that is illegal inside an XML comment. If the generated content would produce `--`, the processor raises an error.
+
+## Attributes
+
+`xsl:comment` takes no attributes.
+
+## Examples
+
+### Adding a generated-by comment
+
+**Input XML:**
+```xml
+
+Summary
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+ Generated from report dated
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+Summary
+```
+
+### HTML conditional comment (legacy)
+
+**Input XML:**
+```xml
+
+Hello
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ [if lt IE 9]><script src="html5shiv.js"></script><![endif]
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+
+Hello
+
+```
+
+## Notes
+
+- The string `--` inside a comment is forbidden by the XML specification. The XSLT processor must raise a dynamic error if the generated comment text contains this sequence. To include a single hyphen safely, write it as a literal hyphen; to include `--` you must redesign the content.
+- Comments are not visible when using `xsl:copy-of` on a node that excludes the comment axis, and they do not contribute to XPath string values.
+- If the output method is `text`, comments are silently ignored — they exist only in tree-oriented output methods (`xml`, `html`).
+- `xsl:comment` content must resolve to text only; you cannot nest element-producing instructions inside it.
+
+## See also
+
+- [xsl:processing-instruction](../xsl-processing-instruction)
+- [xsl:text](../xsl-text)
+- [xsl:output](../xsl-output)
diff --git a/site/content/xslt/functions/xsl-copy-of.md b/site/content/xslt/functions/xsl-copy-of.md
new file mode 100644
index 00000000..03e3b23c
--- /dev/null
+++ b/site/content/xslt/functions/xsl-copy-of.md
@@ -0,0 +1,124 @@
+---
+title: "xsl:copy-of"
+description: "Performs a deep copy of a node-set or value into the result tree, preserving all descendants, attributes, and namespaces."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:copy-of` evaluates the `select` expression and copies the entire result into the output tree. Unlike `xsl:copy`, which copies only the current node shallowly, `xsl:copy-of` performs a **deep copy**: element nodes are copied with all their attributes, namespace nodes, and all descendant nodes recursively.
+
+If the `select` expression yields a node-set, each node in the set is deep-copied in document order. If the expression yields a string, number, or boolean, it is converted to its string representation and output as a text node — which is the same behaviour as `xsl:value-of`.
+
+A particularly important use in XSLT 1.0 is copying result tree fragments stored in variables. A content-based `xsl:variable` produces an RTF, and `xsl:copy-of` is one of the few operations that can emit an RTF into the result tree directly without first converting it to a string.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | XPath expression | Yes | Node-set, value, or variable reference to copy into the output. |
+
+## Examples
+
+### Deep copy of a subtree
+
+**Input XML:**
+```xml
+
+
+
+ Widget
+
+ 0.5
+ blue
+
+
+
+ Gadget
+
+ 1.2
+ red
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Widget
+
+ 0.5
+ blue
+
+
+
+```
+
+### Copying a result tree fragment from a variable
+
+**Input XML:**
+```xml
+
+42
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 42
+ 42
+
+```
+
+## Notes
+
+- `xsl:copy-of` preserves namespace nodes of copied elements. If namespaces from the source document are not desired in the output, you will need to rebuild the elements manually or use `exclude-result-prefixes` on the stylesheet element.
+- Unlike `xsl:value-of`, `xsl:copy-of` does not serialize the node to text — it inserts actual node copies, preserving XML structure.
+- When the select expression is a string or number, `xsl:copy-of` and `xsl:value-of` produce identical results. The meaningful difference arises with node-sets and RTFs.
+- In XSLT 2.0+, `xsl:copy-of` accepts a `copy-namespaces` attribute (`yes` / `no`) to control whether namespace nodes are included in element copies.
+
+## See also
+
+- [xsl:copy](../xsl-copy)
+- [xsl:variable](../xsl-variable)
diff --git a/site/content/xslt/functions/xsl-copy.md b/site/content/xslt/functions/xsl-copy.md
new file mode 100644
index 00000000..6156d7e4
--- /dev/null
+++ b/site/content/xslt/functions/xsl-copy.md
@@ -0,0 +1,122 @@
+---
+title: "xsl:copy"
+description: "Creates a shallow copy of the current node — the node itself but not its children or attributes — into the result tree."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:copy` copies the current context node — and only that node — to the result tree. It is a **shallow** copy: for element nodes, no attributes and no child nodes are included unless you explicitly add them inside the `xsl:copy` body. For text, comment, and processing-instruction nodes, the content is included automatically because those node types have no children.
+
+The most common use of `xsl:copy` is inside the identity transform pattern, where a template matches every node and attribute with `match="@*|node()"`, copies it with `xsl:copy`, and then recursively applies templates to its children. This pattern lets you modify only the parts of a document you care about while passing everything else through unchanged.
+
+When copying an element node, `xsl:copy` also copies the namespace nodes that are in scope for that element, preserving namespace correctness in the output. It does not copy attributes automatically — those must be added explicitly or via `use-attribute-sets`.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `use-attribute-sets` | whitespace-separated QNames | No | Names of `xsl:attribute-set` declarations to expand onto the copied element. |
+
+## Examples
+
+### Identity transform with selective modification
+
+**Input XML:**
+```xml
+
+
+ Draft
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Final
+
+
+```
+
+**Output:**
+```xml
+
+ Final
+
+
+```
+
+### Copying an element and adding an attribute
+
+**Input XML:**
+```xml
+
+
+ - Alpha
+ - Beta
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Alpha
+ - Beta
+
+```
+
+## Notes
+
+- `xsl:copy` applied to an attribute node copies that attribute to the result element. It must be used when the context node is an attribute and you want to preserve it in the output.
+- For a root node, `xsl:copy` copies the root node itself (producing a document node in the result); its children must be processed explicitly.
+- To copy a node together with all its descendants without writing extra templates, use `xsl:copy-of` instead.
+- The identity transform (`match="@*|node()"`) is an essential XSLT pattern for document editing stylesheets. Always place more specific overriding templates after the identity template, or give them higher `priority`.
+
+## See also
+
+- [xsl:copy-of](../xsl-copy-of)
+- [xsl:apply-templates](../xsl-apply-templates)
+- [xsl:attribute-set](../xsl-attribute-set)
diff --git a/site/content/xslt/functions/xsl-decimal-format.md b/site/content/xslt/functions/xsl-decimal-format.md
new file mode 100644
index 00000000..37ac4e3c
--- /dev/null
+++ b/site/content/xslt/functions/xsl-decimal-format.md
@@ -0,0 +1,127 @@
+---
+title: "xsl:decimal-format"
+description: "Defines a named decimal format controlling how format-number() formats numbers in XSLT 1.0 and later."
+date: 2026-04-19T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`xsl:decimal-format` is a top-level declaration that defines the characters and symbols used when `format-number()` converts a numeric value to a string. By giving the format a name you can define multiple locale-specific formats in a single stylesheet, then pass the format name as the third argument to `format-number()`.
+
+If no `name` attribute is given, the declaration sets the default decimal format used when `format-number()` is called with only two arguments. Every attribute has a default value, so you only need to specify the attributes that differ from those defaults.
+
+The `decimal-separator` and `grouping-separator` characters used in the `format` pattern passed to `format-number()` must match those declared in the decimal format — the processor interprets the pattern characters according to the active decimal format.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | No | Name of this format; omit for the default format. |
+| `decimal-separator` | char | No | Character used as the decimal point (default `.`). |
+| `grouping-separator` | char | No | Character used as the thousands separator (default `,`). |
+| `infinity` | string | No | String representing positive infinity (default `Infinity`). |
+| `minus-sign` | char | No | Character used as the minus sign (default `-`). |
+| `NaN` | string | No | String representing NaN (default `NaN`). |
+| `percent` | char | No | Character interpreted as percent in a pattern (default `%`). |
+| `per-mille` | char | No | Character interpreted as per-mille in a pattern (default `‰`). |
+| `zero-digit` | char | No | Digit character representing zero in a pattern (default `0`). |
+| `digit` | char | No | Character representing an optional digit in a pattern (default `#`). |
+| `pattern-separator` | char | No | Separates positive and negative sub-patterns (default `;`). |
+
+## Return value
+
+`xsl:decimal-format` is a declaration; it produces no output.
+
+## Examples
+
+### Formatting numbers with European locale
+
+**Input XML:**
+```xml
+
+
+ 1234567.89
+ 0.5
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 1.234.567,89
+ 0,50
+
+```
+
+### Overriding the default format
+
+**Input XML:**
+```xml
+
+
+ 3.14159
+ -7
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+3.14
+-7
+```
+
+## Notes
+
+- All characters used in a decimal format must be distinct from each other.
+- The `format` picture string passed to `format-number()` is interpreted using the characters declared in the active decimal format, not literal ASCII symbols.
+- In XSLT 2.0, `xsl:decimal-format` gains additional attributes and the semantics align more closely with Unicode CLDR.
+- It is an error to have two `xsl:decimal-format` declarations with the same name (or two unnamed declarations) that differ in any attribute value.
+
+## See also
+
+- [format-number()](../xpath-format-number)
+- [xsl:number](../xsl-number)
diff --git a/site/content/xslt/functions/xsl-element.md b/site/content/xslt/functions/xsl-element.md
new file mode 100644
index 00000000..d0f6031c
--- /dev/null
+++ b/site/content/xslt/functions/xsl-element.md
@@ -0,0 +1,122 @@
+---
+title: "xsl:element"
+description: "Creates an element node in the result tree with a name computed at runtime from an XPath expression."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:element` generates an element in the output whose tag name is determined at transformation time, not written literally in the stylesheet. The `name` attribute is an attribute value template (curly-brace expressions are evaluated and substituted), so it can incorporate source-document data, variable values, or any XPath expression.
+
+When you know the element name in advance, you simply write the literal element directly in the stylesheet — for example `... `. `xsl:element` is only necessary when the element name must be computed dynamically.
+
+The content of `xsl:element` is a template body: any XSLT instructions and literal result elements placed inside become the children and attributes of the generated element. Attributes must be added before any child elements; the typical pattern is to emit `xsl:attribute` children first, then content.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | AVT (QName) | Yes | Name of the element to create. Evaluated as an attribute value template. |
+| `namespace` | AVT (URI) | No | Namespace URI for the created element. Overrides any prefix in `name`. |
+| `use-attribute-sets` | whitespace-separated QNames | No | Attribute sets to expand onto the element. |
+
+## Examples
+
+### Element name from source data
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ alice
+ alice@example.com
+ admin
+
+```
+
+### Computing element name from a variable
+
+**Input XML:**
+```xml
+
+
+ - Widget
+ - Support
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+```
+
+## Notes
+
+- If the computed name is not a valid XML QName, most processors raise an error. Validate source data or use `xsl:choose` to guard against invalid names.
+- `xsl:attribute` children of `xsl:element` must appear before any non-attribute content (text, child elements). Placing them after content is an error.
+- The `namespace` attribute overrides the namespace implied by any prefix in the `name` value. If `name` has a prefix but no `namespace` is provided, the prefix must be bound in the stylesheet's in-scope namespaces.
+- In XSLT 2.0+, `xsl:element` also accepts an `inherit-namespaces` attribute to control whether namespace nodes are inherited by child elements.
+
+## See also
+
+- [xsl:attribute](../xsl-attribute)
+- [xsl:attribute-set](../xsl-attribute-set)
+- [xsl:copy](../xsl-copy)
diff --git a/site/content/xslt/functions/xsl-expose.md b/site/content/xslt/functions/xsl-expose.md
new file mode 100644
index 00000000..fca18dbe
--- /dev/null
+++ b/site/content/xslt/functions/xsl-expose.md
@@ -0,0 +1,134 @@
+---
+title: "xsl:expose"
+description: "Controls the visibility of components in an xsl:package, determining which are accessible to consuming packages."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:expose` is a top-level child of `xsl:package` that sets the visibility of one or more components. Without an `xsl:expose` declaration, all components in a package default to `private` visibility, meaning they are invisible to consuming stylesheets or packages.
+
+The `component` attribute selects the type of component being configured, and the `match` attribute is a name pattern (supporting wildcards) that selects which components of that type are affected. The `visibility` attribute determines how the selected components may be used by packages that include this one via `xsl:use-package`.
+
+The four visibility levels are:
+
+- **`public`** — accessible to consuming packages and may be overridden with `xsl:override`.
+- **`final`** — accessible but may not be overridden; the implementation is fixed.
+- **`private`** — hidden from consuming packages entirely.
+- **`abstract`** — declares the component's signature but provides no implementation; consuming packages must supply one via `xsl:override`.
+
+## Parameters
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `component` | token | Yes | Type of component: `function`, `template`, `variable`, `attribute-set`, `type`, or `mode`. |
+| `match` | pattern | Yes | A name pattern selecting which components are affected. `*` matches all. |
+| `visibility` | token | Yes | One of `public`, `private`, `final`, or `abstract`. |
+
+## Return value
+
+`xsl:expose` is a declaration; it produces no XDM value.
+
+## Examples
+
+### Exposing public functions and keeping helpers private
+
+**Package file:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Using abstract visibility to define a required contract
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Consuming stylesheet providing the required implementation:**
+```xml
+
+
+
+
+
+
+ My Page
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Multiple `xsl:expose` declarations may appear in the same package. If a component matches more than one declaration, the most specific match (by name) takes precedence; the order of declaration is not significant.
+- The `match` attribute uses the same name-pattern syntax as `xsl:apply-templates/@mode` patterns. The wildcard `*` matches any expanded QName.
+- Abstract components must be overridden by every stylesheet that uses the package; failure to do so is a static error.
+- A `final` component may be accepted by a consuming package with `xsl:accept` using a less permissive visibility, but it cannot be overridden.
+
+## See also
+
+- [xsl:package](../xsl-package)
+- [xsl:accept](../xsl-accept)
diff --git a/site/content/xslt/functions/xsl-fallback.md b/site/content/xslt/functions/xsl-fallback.md
new file mode 100644
index 00000000..7e5a00a6
--- /dev/null
+++ b/site/content/xslt/functions/xsl-fallback.md
@@ -0,0 +1,92 @@
+---
+title: "xsl:fallback"
+description: "Provides fallback content to execute when an enclosing extension element or unrecognised instruction is not supported by the processor."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:fallback` supplies an alternative sequence constructor that a conformant processor must use when it encounters an enclosing instruction it does not recognise or does not support. This allows stylesheets to use extension elements or forward-compatible XSLT features while gracefully degrading for processors that lack the capability.
+
+`xsl:fallback` must appear as a direct child of an extension element (an element in a non-XSLT, non-literal-result namespace) or of an XSLT instruction that may not be supported (e.g., `xsl:next-match` in a 1.0 processor). Multiple `xsl:fallback` children may be present; if the enclosing instruction is unsupported, all of them are instantiated in document order.
+
+If the enclosing instruction **is** supported, `xsl:fallback` is silently ignored.
+
+## Parameters
+
+`xsl:fallback` has no attributes. It contains a sequence constructor.
+
+## Return value
+
+The result of the sequence constructor inside `xsl:fallback`, produced when the enclosing instruction is not supported.
+
+## Examples
+
+### Fallback for an XSLT 2.0 instruction in a 1.0 context
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Fallback for a vendor extension element
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+ vendor:render-pdf not supported; using plain output.
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:fallback` is evaluated only when the enclosing instruction is **not** supported. If the instruction succeeds normally, the fallback is skipped entirely.
+- An XSLT processor that encounters an unsupported instruction without an `xsl:fallback` child must raise a dynamic error.
+- In forward-compatible mode (`version` attribute higher than the processor's version), unrecognised instructions are treated as extension elements and `xsl:fallback` is invoked if present.
+- `xsl:fallback` cannot be used as a standalone instruction outside an extension or forward-compatible element context.
+
+## See also
+
+- [xsl:next-match](../xsl-next-match)
+- [xsl:apply-imports](../xsl-apply-imports)
+- [xsl:message](../xsl-message)
diff --git a/site/content/xslt/functions/xsl-fork.md b/site/content/xslt/functions/xsl-fork.md
new file mode 100644
index 00000000..77e1661c
--- /dev/null
+++ b/site/content/xslt/functions/xsl-fork.md
@@ -0,0 +1,105 @@
+---
+title: "xsl:fork"
+description: "Processes a streamed sequence in multiple independent branches simultaneously, enabling multiple aggregations in a single pass over a large document."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: "... "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:fork` solves a fundamental streaming constraint: you can only read a stream once. If you need to compute two different aggregations (say, a count and a sum) over the same streaming input, you would normally need two passes — but streaming prohibits that. `xsl:fork` allows both operations to happen in a *single pass* by running multiple sequence constructors over the same streamed input simultaneously.
+
+Each direct child sequence constructor of `xsl:fork` is evaluated independently against the same input. The results of all branches are concatenated in document order. Branches must be individually streamable — they cannot share state with each other except via accumulators.
+
+`xsl:fork` is only meaningful in a streaming context. Outside streaming it works but is equivalent to simply writing the branches sequentially. The real value is inside `xsl:stream` or inside a streamable template where the input can only be consumed once.
+
+A common pattern is `xsl:fork` containing two or more `xsl:sequence` children, each with a streamable `select` expression (such as `count(//element)` or `sum(//amount)`). Each select is computed in parallel over the single stream.
+
+## Attributes
+
+`xsl:fork` has no element-specific attributes. Its children are sequence constructors forming the independent branches.
+
+## Examples
+
+### Computing count and sum in one streaming pass
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Fork with apply-templates branches
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Each branch of `xsl:fork` must be independently streamable. The branches cannot share variables or communicate except through accumulators.
+- The results of all branches are concatenated in the order the branches appear.
+- `xsl:fork` can contain `xsl:fallback` to handle non-streaming processors gracefully.
+- Using `xsl:fork` outside a streaming context is valid but adds no value — branches execute sequentially.
+- Processors may or may not truly parallelise the branches; the specification only requires that the result is as-if they ran simultaneously.
+
+## See also
+
+- [xsl:stream](../xsl-stream)
+- [xsl:merge](../xsl-merge)
+- [xsl:accumulator](../xsl-accumulator)
diff --git a/site/content/xslt/functions/xsl-if.md b/site/content/xslt/functions/xsl-if.md
new file mode 100644
index 00000000..786180df
--- /dev/null
+++ b/site/content/xslt/functions/xsl-if.md
@@ -0,0 +1,118 @@
+---
+title: "xsl:if"
+description: "Conditionally outputs content when a boolean XPath expression evaluates to true; has no else branch."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:if` evaluates the XPath expression in its `test` attribute and instantiates its content only when the result is true (or converts to boolean true). When the expression is false, the element and all its children are silently skipped — no output is produced.
+
+Because `xsl:if` has no else branch, use `xsl:choose` with `xsl:when` and `xsl:otherwise` when you need to handle two or more mutually exclusive cases. For a simple true/false toggle, `xsl:if` is more concise and readable.
+
+The `test` expression is evaluated in the current context and can reference context-node content, positional functions like `position()` and `last()`, variables, and any XPath 1.0 expression. Non-boolean results are coerced to boolean according to XPath rules: a non-empty node-set is true, a non-zero number is true, and a non-empty string is true.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `test` | Boolean XPath expression | Yes | Expression that controls whether the content is output. |
+
+## Examples
+
+### Conditional row class
+
+**Input XML:**
+```xml
+
+
+ - Widget
+ - Gadget
+ - Doohickey
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+ out-of-stock
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Widget 5
+ Gadget 0
+ Doohickey 12
+
+```
+
+### Alternate row separator
+
+**Input XML:**
+```xml
+
+
+ Red
+ Green
+ Blue
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ ,
+
+
+
+
+
+```
+
+**Output:**
+```
+Red, Green, Blue
+```
+
+## Notes
+
+- `xsl:if` cannot appear at the top level of a stylesheet; it is only valid inside a template body.
+- An empty node-set converts to boolean `false`, so `` is a safe existence check.
+- Comparing a missing attribute to a value (e.g., `@attr = 'x'`) returns `false` rather than raising an error, because the attribute node-set is empty.
+- For multiple exclusive branches, use `xsl:choose` instead of chaining several `xsl:if` elements — the latter evaluates all conditions independently, which is rarely the desired behaviour.
+
+## See also
+
+- [xsl:choose](../xsl-choose)
+- [xsl:when](../xsl-when)
+- [xsl:otherwise](../xsl-otherwise)
diff --git a/site/content/xslt/functions/xsl-import-schema.md b/site/content/xslt/functions/xsl-import-schema.md
new file mode 100644
index 00000000..59b9cde9
--- /dev/null
+++ b/site/content/xslt/functions/xsl-import-schema.md
@@ -0,0 +1,120 @@
+---
+title: "xsl:import-schema"
+description: "Imports an XML Schema to enable schema-aware processing, typed variable declarations, and validation of input and output documents."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:import-schema` is a top-level declaration that imports an XML Schema into the stylesheet. Once imported, the schema's type definitions become available for:
+
+- Type annotations in `as` attributes on variables, parameters, and functions.
+- Schema-aware matching patterns such as `element(*, xs:integer)`.
+- Input validation via `xsl:validate` (Saxon-EE).
+- Output validation using the `validation` attribute on result elements.
+
+Schema-aware processing is an optional feature of XSLT 2.0 and requires a schema-aware processor such as Saxon-EE. Saxon-HE and Saxon-PE do not support schema import.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `namespace` | URI | No | The target namespace of the schema to import. Omit for schemas with no target namespace. |
+| `schema-location` | URI | No | Hint to the processor about where to find the schema document. |
+
+Content: may contain an inline `xs:schema` element instead of using `schema-location`.
+
+## Return value
+
+No direct output. Populates the in-scope schema definitions for the stylesheet.
+
+## Examples
+
+### Importing a schema and using typed variables
+
+**Schema (`order.xsd`):**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Importing a no-namespace schema inline
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:import-schema` requires a **schema-aware** XSLT 2.0 processor. Saxon-HE does not support this feature.
+- The `schema-location` attribute is only a hint; processors may find the schema by namespace alone if they maintain a schema catalog.
+- Importing a schema does not automatically validate the source document. Use the `validation` attribute on `xsl:apply-templates` or `xsl:result-document` for validation.
+- Multiple schemas may be imported by using several `xsl:import-schema` elements; circular imports are allowed if they mirror valid schema inclusion patterns.
+
+## See also
+
+- [xsl:namespace](../xsl-namespace)
+- [xsl:function](../xsl-function)
+- [xsl:output](../xsl-output)
diff --git a/site/content/xslt/functions/xsl-import.md b/site/content/xslt/functions/xsl-import.md
new file mode 100644
index 00000000..4247f091
--- /dev/null
+++ b/site/content/xslt/functions/xsl-import.md
@@ -0,0 +1,129 @@
+---
+title: "xsl:import"
+description: "Imports another stylesheet at a lower import precedence, allowing the importing stylesheet to override any of its declarations."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:import` brings in the top-level declarations of another stylesheet but assigns them a **lower import precedence** than the importing stylesheet's own declarations. This means that templates, variables, and other declarations in the importing stylesheet automatically override conflicting declarations from the imported stylesheet. The imported stylesheet in turn may import further stylesheets at even lower precedence.
+
+This precedence hierarchy makes `xsl:import` the standard mechanism for stylesheet inheritance and customisation. A base library provides default behaviour; a project stylesheet imports it and overrides only the parts it needs. Inside an overriding template, `xsl:apply-imports` can call the lower-precedence (imported) version — the equivalent of `super()` in object-oriented languages.
+
+`xsl:import` must be the first children of `xsl:stylesheet`, before any other top-level declarations, including other `xsl:import` elements from earlier imports. If multiple `xsl:import` elements exist, the one that appears last has the highest precedence among the imported stylesheets.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `href` | URI reference | Yes | Location of the stylesheet to import. Resolved relative to the importing stylesheet's base URI. |
+
+## Examples
+
+### Base library with override
+
+**base.xsl** (the imported library):
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**custom.xsl** (the importing stylesheet):
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Input XML:**
+```xml
+
+
+ Hello world .
+
+```
+
+**Output:**
+```xml
+
+
+
+```
+
+### Cascading imports
+
+**Input XML:**
+```xml
+
+- Test
+```
+
+**layer1.xsl**:
+```xml
+
+
+
+
+```
+
+**layer2.xsl** (imports layer1, overrides item):
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+```
+
+## Notes
+
+- `xsl:import` elements must precede all other top-level children. Placing them after any template, variable, or `xsl:output` declaration is an error.
+- Circular imports are forbidden and must be detected by the processor.
+- `xsl:apply-imports` can only be used inside a template that has overridden an imported template; it calls the best-matching template at a lower import precedence.
+- Multiple `xsl:import` elements are evaluated so that the last listed `xsl:import` has the highest precedence among the imported stylesheets (but still lower than the importing stylesheet itself).
+
+## See also
+
+- [xsl:include](../xsl-include)
+- [xsl:stylesheet](../xsl-stylesheet)
+- [xsl:apply-templates](../xsl-apply-templates)
diff --git a/site/content/xslt/functions/xsl-include.md b/site/content/xslt/functions/xsl-include.md
new file mode 100644
index 00000000..a5e99586
--- /dev/null
+++ b/site/content/xslt/functions/xsl-include.md
@@ -0,0 +1,120 @@
+---
+title: "xsl:include"
+description: "Merges another stylesheet's top-level declarations into the current stylesheet at the same import precedence."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:include` incorporates the top-level declarations of another stylesheet into the including stylesheet as if they had been written there directly. Unlike `xsl:import`, the included declarations have the **same import precedence** as the declarations in the including stylesheet. This means there is no override relationship — conflicts between included and including templates follow the same conflict-resolution rules as ordinary duplicates (a processor may signal an error or choose the last declaration).
+
+`xsl:include` is the right choice when you want to split a large stylesheet into modular files that all operate at the same level. Common patterns include separating formatting templates, utility named templates, and domain-specific rules into distinct files that are included by a master stylesheet.
+
+`xsl:include` must appear as a top-level child of `xsl:stylesheet`, and it must appear after all `xsl:import` elements but before any templates, variable declarations, or other top-level declarations.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `href` | URI reference | Yes | Location of the stylesheet to include. Resolved relative to the including stylesheet's base URI. |
+
+## Examples
+
+### Modular stylesheet organisation
+
+**utilities.xsl** (the included file):
+```xml
+
+
+
+
+
+
+
+
+
+```
+
+**main.xsl** (the including stylesheet):
+```xml
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+```
+
+**Input XML:**
+```xml
+
+
+ hello
+ world
+
+```
+
+**Output:**
+```xml
+
+ - Hello
+ - World
+
+```
+
+### Including a shared output configuration
+
+**output-settings.xsl**:
+```xml
+
+
+
+
+```
+
+**page.xsl**:
+```xml
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Circular inclusion (A includes B which includes A) is an error. Processors must detect and reject cycles.
+- Because included declarations have the same precedence as the including stylesheet's own declarations, duplicate template rules may cause conflict. Use `xsl:import` if you want a clear override relationship.
+- `xsl:include` is resolved at stylesheet load time, not at transformation time; the referenced URI must be accessible when the processor compiles the stylesheet.
+- The included stylesheet's own `xsl:output` declarations merge with those of the including stylesheet. When there are conflicts, the `xsl:output` attribute from the stylesheet with higher import precedence wins.
+
+## See also
+
+- [xsl:import](../xsl-import)
+- [xsl:stylesheet](../xsl-stylesheet)
diff --git a/site/content/xslt/functions/xsl-key.md b/site/content/xslt/functions/xsl-key.md
new file mode 100644
index 00000000..ae9543dd
--- /dev/null
+++ b/site/content/xslt/functions/xsl-key.md
@@ -0,0 +1,135 @@
+---
+title: "xsl:key"
+description: "Defines a named index for efficiently selecting nodes using the key() function in XSLT 1.0 and later."
+date: 2026-04-19T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`xsl:key` declares a named index that associates nodes matched by the `match` pattern with key values computed by the `use` expression. Once declared, the `key()` function retrieves nodes from this index in constant time regardless of document size, making it the preferred technique for cross-referencing nodes.
+
+Keys are declared as top-level elements of the stylesheet. Multiple `xsl:key` declarations with the same name accumulate: a node is indexed under a key value if any of the declarations with that name assigns that value to it. This makes it straightforward to build multi-column indexes.
+
+The `use` expression is evaluated with the matched node as the context node. If `use` returns a node-set, each node in the set contributes a separate key value. String values are compared after whitespace normalization using the default collation.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | The name used to reference this key in the `key()` function. |
+| `match` | pattern | Yes | An XSLT pattern identifying which nodes are indexed by this key. |
+| `use` | expression | Yes | An XPath expression evaluated for each matched node to determine its key value(s). |
+
+## Return value
+
+`xsl:key` is a declaration — it produces no output. It instructs the processor to build an index that is queried via the `key()` function.
+
+## Examples
+
+### Looking up products by category
+
+**Input XML:**
+```xml
+
+
+ Laptop
+ XPath Guide
+ Tablet
+ XSLT Cookbook
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Laptop
+ - Tablet
+
+```
+
+### Muenchian grouping by first letter
+
+**Input XML:**
+```xml
+
+
+ Alice
+ Bob
+ Anna
+ Brian
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ Alice
+ Anna
+
+
+ Bob
+ Brian
+
+
+```
+
+## Notes
+
+- `xsl:key` must appear as a top-level child of `xsl:stylesheet` or `xsl:transform`.
+- The Muenchian grouping technique relies on `xsl:key` combined with `generate-id()` and is the standard XSLT 1.0 method for grouping nodes.
+- In XSLT 2.0 and later, `xsl:for-each-group` supersedes Muenchian grouping for most use cases, but `xsl:key` remains useful for random-access lookups.
+- Keys built from large documents are cached by the processor and reused across multiple `key()` calls.
+
+## See also
+
+- [key()](../xpath-key)
+- [xsl:for-each](../xsl-for-each)
+- [generate-id()](../xpath-generate-id)
diff --git a/site/content/xslt/functions/xsl-map-entry.md b/site/content/xslt/functions/xsl-map-entry.md
new file mode 100644
index 00000000..06f4ab34
--- /dev/null
+++ b/site/content/xslt/functions/xsl-map-entry.md
@@ -0,0 +1,112 @@
+---
+title: "xsl:map-entry"
+description: "Adds a single key-value pair to an xsl:map, where the key is any atomic value and the value is any XDM sequence."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:map-entry` contributes a single key-value pair to the enclosing `xsl:map`. The `key` attribute is an XPath expression that must evaluate to a single atomic value — strings, integers, dates, and QNames are all valid key types. The value is provided either via the `select` attribute or via a sequence constructor in the element content.
+
+Because `xsl:map-entry` is an XSLT instruction, you can use it inside `xsl:for-each` to programmatically add entries, or inside `xsl:if`/`xsl:choose` to conditionally include entries. This makes `xsl:map-entry` more flexible than the XPath `map{...}` constructor syntax when the data is dynamic.
+
+Keys within a single map must be distinct. Two atomic values are equal as map keys if they are equal according to the `eq` operator with the same implicit timezone. If the same key appears twice in the `xsl:map`, the processor raises error `XTDE3365`.
+
+The value can be any XDM sequence including the empty sequence, nodes, arrays, and even nested maps, making `xsl:map-entry` the building block for arbitrarily nested data structures.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `key` | expression | Yes | XPath expression evaluating to a single atomic value. |
+| `select` | expression | No | XPath expression providing the map value. If absent, the content sequence constructor is used. |
+
+## Examples
+
+### Building a map conditionally
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 30
+ true
+
+```
+
+### Nested maps for structured data
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- If the `key` expression returns more than one atomic value, error `XTTE3360` is raised.
+- If the `key` expression returns a node, it is atomised to its typed value automatically.
+- An empty-sequence key raises an error; use `(expr, '')[1]` to provide a fallback.
+- When using integer keys, beware that `1` (xs:integer) and `1.0` (xs:decimal) are equal as map keys.
+
+## See also
+
+- [xsl:map](../xsl-map)
+- [map:get()](../xpath-map-get)
+- [map:merge()](../xpath-map-merge)
diff --git a/site/content/xslt/functions/xsl-map.md b/site/content/xslt/functions/xsl-map.md
new file mode 100644
index 00000000..e403d45b
--- /dev/null
+++ b/site/content/xslt/functions/xsl-map.md
@@ -0,0 +1,106 @@
+---
+title: "xsl:map"
+description: "Creates an XDM map from one or more xsl:map-entry children, enabling key-value data structures directly in XSLT 3.0 stylesheets."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: " "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:map` is the instruction form for constructing an XDM map — an unordered collection of key-value pairs where keys are atomic values and values can be any XDM sequence. Maps were added to XDM in version 3.1 and are central to working with JSON in XSLT 3.0.
+
+The instruction form `xsl:map` is an alternative to the XPath constructor `map{key: value, ...}`. Use the instruction form when you want to build a map from dynamic content using sequence constructors, loops, or conditional logic. You can mix `xsl:map-entry` children with `xsl:if`, `xsl:for-each`, and other instructions to build the map programmatically.
+
+Maps are immutable but can be merged using XPath `map:merge()`. They are particularly useful as lookup tables, configuration objects passed to named templates, and intermediate data structures when generating JSON output via `xsl:output method="json"`.
+
+Keys must be atomic values and must be unique within a map. Attempting to add duplicate keys raises an error unless you use `map:merge()` with an appropriate `duplicates` option.
+
+## Attributes
+
+`xsl:map` has no element-specific attributes. Its content must consist of `xsl:map-entry` instructions (and other XSLT instructions that produce map entries).
+
+## Examples
+
+### Building a lookup table from XML data
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - 19.99
+ - N/A
+
+```
+
+### Generating JSON output from a map
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:map` produces a single map item, not a sequence of nodes. You cannot mix map entries and node constructors in the same `xsl:map`.
+- The XPath expression form `map{k1: v1, k2: v2}` is equivalent and more concise when the keys and values are known at compile time.
+- To merge two maps, use the XPath function `map:merge(($map1, $map2))`.
+- Maps are not serialised by default in XML output mode; to include them in output, convert to XML or use JSON output.
+
+## See also
+
+- [xsl:map-entry](../xsl-map-entry)
+- [map:get()](../xpath-map-get)
+- [map:merge()](../xpath-map-merge)
diff --git a/site/content/xslt/functions/xsl-matching-substring.md b/site/content/xslt/functions/xsl-matching-substring.md
new file mode 100644
index 00000000..57bbc4be
--- /dev/null
+++ b/site/content/xslt/functions/xsl-matching-substring.md
@@ -0,0 +1,117 @@
+---
+title: "xsl:matching-substring"
+description: "Defines the template body applied to each substring that matches the regex inside xsl:analyze-string."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:matching-substring` is a child element of `xsl:analyze-string`. Its body is instantiated once for each substring of the analyzed string that matches the regular expression. Inside this element, the context item (`.`) is the matched substring as a string, and `regex-group(n)` returns captured groups.
+
+The element has no attributes. It is optional — omitting it effectively discards all matching substrings from the output.
+
+## Parameters
+
+`xsl:matching-substring` has no attributes. It contains a sequence constructor (any XSLT instructions or literal result elements).
+
+## Return value
+
+The nodes or atomic values produced by the sequence constructor, contributed to the output of the enclosing `xsl:analyze-string`.
+
+## Examples
+
+### Wrapping matched words in emphasis tags
+
+**Input XML:**
+```xml
+
+The quick brown fox jumps over the lazy dog.
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+The quick brown fox jumps over the lazy dog .
+```
+
+### Reformatting phone numbers with groups
+
+**Input XML:**
+```xml
+
+
+ 0034912345678
+ 0044207946000
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ +34 912345678
+ +44 207946000
+
+```
+
+## Notes
+
+- `xsl:matching-substring` is only valid as a direct child of `xsl:analyze-string`.
+- The context item inside this element is always a string (the matched text), not the original node.
+- Use `regex-group(0)` to get the full match, or `regex-group(n)` for the *n*th parenthesized group.
+- If no matches are found, `xsl:matching-substring` is never instantiated.
+
+## See also
+
+- [xsl:analyze-string](../xsl-analyze-string)
+- [xsl:non-matching-substring](../xsl-non-matching-substring)
+- [regex-group()](../xpath-regex-group)
diff --git a/site/content/xslt/functions/xsl-merge-action.md b/site/content/xslt/functions/xsl-merge-action.md
new file mode 100644
index 00000000..ad013d75
--- /dev/null
+++ b/site/content/xslt/functions/xsl-merge-action.md
@@ -0,0 +1,106 @@
+---
+title: "xsl:merge-action"
+description: "Defines the body executed for each group of items sharing the same merge key during an xsl:merge operation, with access to the merged items and current key."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: "... "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:merge-action` is the body of an `xsl:merge` instruction. It is executed once for each distinct merge key value encountered across all sources. When multiple sources have items with the same key, all such items are collected into the `$current-merge-group` variable, and the action is called once for the entire group.
+
+Inside `xsl:merge-action`, two implicit variables are always available:
+
+- `$current-merge-key` — the atomic value of the current merge key (for compound keys, this is the primary key; use `current-merge-key()` function for the full key).
+- `$current-merge-group` — a sequence containing all items from all merge sources whose key matches the current key. The items appear in source declaration order, and items from earlier-declared sources come before items from later-declared sources with the same key.
+
+You can also call `current-merge-group('source-name')` to get items from a specific named source, enabling source-specific processing within a merge action.
+
+`xsl:merge-action` must be a direct child of `xsl:merge` and there must be exactly one. Any XSLT instructions may appear inside it — `xsl:if`, `xsl:for-each`, `xsl:choose`, `xsl:copy-of`, and so on.
+
+## Attributes
+
+`xsl:merge-action` has no element-specific attributes. It contains a sequence constructor.
+
+## Examples
+
+### Combining matching items from two sources
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Generating summaries per key group
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `$current-merge-group` is a sequence; use `count()`, `sum()`, `for-each`, or other sequence operations on it.
+- `current-merge-group('name')` returns items from one named source only. Items appear in document order within that source.
+- When only one source contributes to a key group, `current-merge-group('other-source')` returns the empty sequence.
+- `xsl:merge-action` is streamable if its content is streamable.
+
+## See also
+
+- [xsl:merge](../xsl-merge)
+- [xsl:merge-source](../xsl-merge-source)
+- [xsl:merge-key](../xsl-merge-key)
diff --git a/site/content/xslt/functions/xsl-merge-key.md b/site/content/xslt/functions/xsl-merge-key.md
new file mode 100644
index 00000000..5ba22e36
--- /dev/null
+++ b/site/content/xslt/functions/xsl-merge-key.md
@@ -0,0 +1,107 @@
+---
+title: "xsl:merge-key"
+description: "Defines the sort key for items in an xsl:merge-source, determining how items from different sources are aligned and interleaved during merging."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:merge-key` is a child of `xsl:merge-source` that specifies how items in a merge source are ordered. Each `xsl:merge-source` must have at least one `xsl:merge-key`. If you need a compound sort key (for example, sort by year then by month), use multiple `xsl:merge-key` elements — the first is the primary key, the second is secondary, and so on.
+
+The `select` expression is evaluated once for each item in the merge source, with the item as the context node. The result must be a single atomic value (or the empty sequence, which sorts last). All merge sources must declare the same number of `xsl:merge-key` elements with compatible key types and the same sort order.
+
+The `order`, `data-type`, `case-order`, `lang`, and `collation` attributes mirror the corresponding attributes on `xsl:sort` and work identically. This means you can sort by date using `xs:date(@date)` and get correct chronological ordering, sort alphabetically with collation support, or sort by numeric value.
+
+Getting merge keys right is critical: the `xsl:merge` instruction trusts that each source is already sorted by its declared keys. If any source is out of order, the merge output will be incorrect without any error being raised by most processors.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | expression | No | Key expression evaluated for each item. Default is `.` (the item itself). |
+| `order` | `ascending\|descending` | No | Sort direction. Default `ascending`. |
+| `data-type` | `text\|number` | No | Whether to sort as text or number. Default `text`. |
+| `case-order` | token | No | `upper-first` or `lower-first`. |
+| `lang` | language | No | Language for text comparison. |
+| `collation` | URI | No | Collation URI for string comparison. |
+
+## Examples
+
+### Compound merge key: year and month
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Date-typed merge key for chronological ordering
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- All merge sources in the same `xsl:merge` must have the same number of `xsl:merge-key` children with comparable types and identical `order` values.
+- Using `xs:date()` or `xs:dateTime()` for date keys gives correct chronological comparison; string comparison of date strings would fail for unsorted years.
+- The `collation` attribute can be used for locale-aware string merging.
+- Empty sequence keys are placed last in ascending order.
+
+## See also
+
+- [xsl:merge](../xsl-merge)
+- [xsl:merge-source](../xsl-merge-source)
+- [xsl:merge-action](../xsl-merge-action)
diff --git a/site/content/xslt/functions/xsl-merge-source.md b/site/content/xslt/functions/xsl-merge-source.md
new file mode 100644
index 00000000..1d8de50b
--- /dev/null
+++ b/site/content/xslt/functions/xsl-merge-source.md
@@ -0,0 +1,106 @@
+---
+title: "xsl:merge-source"
+description: "Defines one sorted input sequence for xsl:merge, specifying the source data and its merge keys so the merge algorithm can interleave items correctly."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:merge-source` is a child of `xsl:merge` that declares one of the input sequences to be merged. Each source specifies *what* data to read (via `select`) and *how* to identify its sort key (via one or more `xsl:merge-key` children). The `xsl:merge` processor interleaves items from all sources in key order, processing each key group through `xsl:merge-action`.
+
+The `name` attribute gives the source an identifier that is available inside `xsl:merge-action` as part of `$current-merge-group` context — you can distinguish which source an item came from using `xsl:merge-source` context functions.
+
+The `select` expression may reference any sequence, including documents, collections, or streaming sources. When `streamable="yes"` is specified, the source is processed without buffering, enabling large-file merges.
+
+The `use-accumulators` attribute lists accumulators that should be active while reading items from this source. This is especially useful when the source document itself needs accumulated state (such as running totals or section headers) while being streamed.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | NCName | Yes | Identifies this source within `xsl:merge`. |
+| `select` | expression | Yes | The sequence of items to merge from this source. |
+| `streamable` | `yes\|no` | No | Whether this source should be processed in streaming mode. Default `no`. |
+| `use-accumulators` | names | No | Accumulators active while reading from this source. |
+| `sort-before-merge` | `yes\|no` | No | If `yes`, the processor sorts this source before merging. Default `no`. |
+| `validation` | token | No | `strict`, `lax`, or `preserve`. Default `preserve`. |
+
+## Examples
+
+### Two named merge sources from different documents
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Streaming merge source from a collection
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- All `xsl:merge-source` elements within an `xsl:merge` must use the same number of `xsl:merge-key` children with compatible types and orders.
+- The `name` attribute is required even when there is only one source.
+- If `sort-before-merge="no"` (the default), the source data must already be sorted by the merge keys. Providing unsorted data produces incorrect results.
+- In `xsl:merge-action`, use `current-merge-group('source-name')` to get items from a specific named source.
+
+## See also
+
+- [xsl:merge](../xsl-merge)
+- [xsl:merge-key](../xsl-merge-key)
+- [xsl:merge-action](../xsl-merge-action)
diff --git a/site/content/xslt/functions/xsl-merge.md b/site/content/xslt/functions/xsl-merge.md
new file mode 100644
index 00000000..b210dfc0
--- /dev/null
+++ b/site/content/xslt/functions/xsl-merge.md
@@ -0,0 +1,123 @@
+---
+title: "xsl:merge"
+description: "Merges multiple pre-sorted sequences into a single sorted sequence, processing each group of items with the same merge key via xsl:merge-action."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: "... "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:merge` performs a sorted merge of two or more input sequences, each pre-sorted by a common key. It is the XSLT 3.0 equivalent of the merge step in a merge sort algorithm. The processor reads from each source in lockstep, advancing whichever source has the smallest current key, and passes each key-group to `xsl:merge-action` for processing.
+
+This is particularly powerful for combining large datasets that cannot all be loaded into memory simultaneously. Each source can be a collection of documents, a selection from an existing tree, or a streaming source. The merge happens in a single pass and does not require the processor to hold the entire merged result in memory.
+
+Each `xsl:merge` must have at least one `xsl:merge-source` child (usually two or more) and exactly one `xsl:merge-action` child. The merge sources must each be sorted by the same set of `xsl:merge-key` expressions. Inside `xsl:merge-action`, the variable `$current-merge-key` holds the current key value, and the variable `$current-merge-group` holds the sequence of items from all sources that share that key.
+
+## Attributes
+
+`xsl:merge` has no element-specific attributes. Its structure is defined entirely by its children: one or more `xsl:merge-source` elements and exactly one `xsl:merge-action` element.
+
+## Examples
+
+### Merging two sorted XML files by date
+
+**Source 1 (transactions-2026-q1.xml):**
+```xml
+
+
+
+
+
+```
+
+**Source 2 (transactions-2026-q2.xml):**
+```xml
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+
+
+```
+
+### Merging with aggregation on common keys
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- All sources must be pre-sorted by the merge keys in the same order (ascending/descending). The processor does not sort them.
+- `$current-merge-key` and `$current-merge-group` are automatically available inside `xsl:merge-action`.
+- `xsl:merge` is streamable: each source can be a streaming source as long as individual sources do not need to be revisited.
+- When two sources have identical keys, their items are merged into the same `$current-merge-group`.
+
+## See also
+
+- [xsl:merge-source](../xsl-merge-source)
+- [xsl:merge-key](../xsl-merge-key)
+- [xsl:merge-action](../xsl-merge-action)
+- [xsl:stream](../xsl-stream)
diff --git a/site/content/xslt/functions/xsl-message.md b/site/content/xslt/functions/xsl-message.md
new file mode 100644
index 00000000..e8cfe2aa
--- /dev/null
+++ b/site/content/xslt/functions/xsl-message.md
@@ -0,0 +1,119 @@
+---
+title: "xsl:message"
+description: "Emits a diagnostic message to the processor's error output; optionally terminates transformation with terminate='yes'."
+date: 2026-04-19T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: "message content "
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`xsl:message` sends a diagnostic message to the XSLT processor's message destination, which is typically standard error or a log. The content of the element is a sequence constructor: any combination of literal text, value-of, elements, or other instructions that would be legal inside a template. The resulting nodes form the message.
+
+When `terminate="yes"`, the processor stops the transformation immediately after emitting the message and reports an error. This is useful for asserting preconditions at the start of a transformation or validating input data before processing begins.
+
+The exact format and destination of messages is implementation-defined. Saxon writes them to standard error; other processors may write to a log file or fire a callback.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `terminate` | `yes` or `no` | No | When `yes`, the processor stops the transformation after emitting the message (default `no`). |
+| `select` | expression | No | XPath 2.0+ alternative to element content for specifying the message. |
+| `error-code` | QName | No | XSLT 3.0. An error code attached to the message when `terminate="yes"`. |
+
+## Return value
+
+`xsl:message` produces no nodes in the result tree.
+
+## Examples
+
+### Validation guard with terminate
+
+**Input XML:**
+```xml
+
+
+ - Widget
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ ERROR: Negative quantity found for item:
+
+
+
+
+
+```
+
+**Output (message sent to error output, transformation aborted):**
+```
+ERROR: Negative quantity found for item: Widget
+```
+
+### Logging progress without termination
+
+**Input XML:**
+```xml
+
+
+ Alpha
+ Beta
+ Gamma
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ Processing record id=
+
+
+
+
+
+```
+
+**Result tree:**
+```xml
+
+ - Alpha
+ - Beta
+ - Gamma
+
+```
+
+Messages `Processing record id=1`, `Processing record id=2`, and `Processing record id=3` are sent to error output.
+
+## Notes
+
+- The message destination is processor-dependent and cannot be configured from within the stylesheet in XSLT 1.0. Use processor-specific APIs or command-line flags to redirect messages.
+- In XSLT 2.0 and later, `xsl:message` can use the `select` attribute as an alternative to element content.
+- In XSLT 3.0, `terminate="yes"` combined with `error-code` allows catching the error with `try/catch` in the calling stylesheet.
+- Avoid leaving `terminate="no"` messages in production stylesheets without purpose; they slow down transformation and pollute logs.
+
+## See also
+
+- [xsl:if](../xsl-if)
+- [error()](../xpath-error)
+- [trace()](../xpath-trace)
diff --git a/site/content/xslt/functions/xsl-mode.md b/site/content/xslt/functions/xsl-mode.md
new file mode 100644
index 00000000..8517e18b
--- /dev/null
+++ b/site/content/xslt/functions/xsl-mode.md
@@ -0,0 +1,128 @@
+---
+title: "xsl:mode"
+description: "Declares a named mode and its default behaviour when no template matches, enabling modular transformation strategies in XSLT 3.0."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:mode` is a top-level declaration that gives a named mode an explicit identity and sets its default behaviour when the processor encounters a node for which no matching template exists. In XSLT 2.0 you could use modes informally by naming them in `match` and `apply-templates` attributes, but you had no way to declare what should happen on an unmatched node. XSLT 3.0 fixes this with `xsl:mode`.
+
+The most common use is the *identity transform* shortcut: by setting `on-no-match="shallow-copy"` on the unnamed default mode you get automatic element-and-attribute copying without writing a boilerplate identity template. More specialised modes might use `deep-copy` to recursively copy entire subtrees, or `fail` to make missing templates a hard error during development.
+
+Beyond the default mode you can declare any number of named modes, each with its own `on-no-match` policy. This makes it straightforward to implement a pipeline inside a single stylesheet: one mode normalises, another enriches, a third serialises, and each falls back gracefully when a node does not need special handling.
+
+`xsl:mode` can also carry `streamable="yes"` to opt a mode into streaming processing, and `use-accumulators` to list which accumulators are active while templates in that mode fire.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | No | Mode name. Omit (or use `#default`) for the unnamed default mode. |
+| `on-no-match` | token | No | What to do when no template matches. One of `shallow-copy` (default for unnamed mode when declared), `deep-copy`, `shallow-skip`, `deep-skip`, `text-only-copy`, or `fail`. |
+| `streamable` | `yes\|no` | No | Whether templates in this mode must be streamable. Default `no`. |
+| `use-accumulators` | names | No | Space-separated list of accumulator names active in this mode. |
+| `visibility` | token | No | `public`, `private`, or `final` — relevant when packaging. |
+| `warning-on-no-match` | `yes\|no` | No | Emit a warning when `on-no-match` triggers. Default is processor-defined. |
+
+## Examples
+
+### Identity transform using on-no-match
+
+The classic use: copy the whole document and override only the nodes you care about.
+
+**Input XML:**
+```xml
+
+
+ Q1 Results
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Q1 Results
+
+
+```
+
+### Named mode with fail policy for strict transformations
+
+Use a named mode that throws an error on any unmatched element, useful during development to catch gaps in coverage.
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:mode` is a top-level element and must be a direct child of `xsl:stylesheet` or `xsl:transform`.
+- When no `xsl:mode` declaration exists for the default mode, XSLT 3.0 processors behave as in 2.0 (built-in text and element templates).
+- `on-no-match="shallow-copy"` replaces the classic identity template pattern; you no longer need to write ` `.
+- Multiple `xsl:mode` declarations for the same mode name in different packages can be composed via `xsl:use-package`.
+
+## See also
+
+- [xsl:template](../xsl-template)
+- [xsl:apply-templates](../xsl-apply-templates)
+- [xsl:use-accumulators](../xsl-use-accumulators)
+- [xsl:package](../xsl-package)
diff --git a/site/content/xslt/functions/xsl-namespace-alias.md b/site/content/xslt/functions/xsl-namespace-alias.md
new file mode 100644
index 00000000..8d8f3411
--- /dev/null
+++ b/site/content/xslt/functions/xsl-namespace-alias.md
@@ -0,0 +1,123 @@
+---
+title: "xsl:namespace-alias"
+description: "Maps a namespace prefix used in the stylesheet to a different prefix in the result tree, enabling stylesheets that generate XSLT."
+date: 2026-04-19T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`xsl:namespace-alias` solves the problem of writing an XSLT stylesheet whose output is itself an XSLT stylesheet. Normally, elements in the XSLT namespace are interpreted as instructions by the processor. By declaring an alias, you can use a substitute prefix in the stylesheet source while the processor emits the real XSLT namespace URI in the result.
+
+The `stylesheet-prefix` is the stand-in prefix used inside the stylesheet. Any literal result element in that namespace is treated as a literal result element (not an XSLT instruction), and when serialized its namespace URI is replaced by the URI bound to `result-prefix`. Both prefixes must be declared in scope at the point the `xsl:namespace-alias` declaration appears.
+
+This element must appear as a top-level child of `xsl:stylesheet`.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `stylesheet-prefix` | NCName or `#default` | Yes | The prefix used in the stylesheet source as a stand-in. Use `#default` for the default namespace. |
+| `result-prefix` | NCName or `#default` | Yes | The prefix whose namespace URI should appear in the output. Use `#default` for the default namespace. |
+
+## Return value
+
+`xsl:namespace-alias` is a declaration; it produces no output.
+
+## Examples
+
+### Generating an XSLT stylesheet
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+### Aliasing to the default namespace
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:namespace-alias` is primarily used when a stylesheet generates another stylesheet as its output.
+- The aliased prefix namespace URI must not equal the stylesheet namespace URI `http://www.w3.org/1999/XSL/Transform` or the processor will reject the stylesheet.
+- In XSLT 2.0 and later, the same technique works identically; there is no new syntax for this feature in later versions.
+- Only namespace URIs are aliased, not prefix strings. The prefix appearing in the output depends on how the processor serializes namespace bindings.
+
+## See also
+
+- [xsl:output](../xsl-output)
+- [xsl:import](../xsl-import)
diff --git a/site/content/xslt/functions/xsl-namespace.md b/site/content/xslt/functions/xsl-namespace.md
new file mode 100644
index 00000000..845c73cb
--- /dev/null
+++ b/site/content/xslt/functions/xsl-namespace.md
@@ -0,0 +1,106 @@
+---
+title: "xsl:namespace"
+description: "Creates a namespace node on the current element, binding a prefix to a namespace URI dynamically."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:namespace` adds a namespace node to the element being constructed. It is the programmatic equivalent of writing `xmlns:prefix="uri"` as a literal attribute, but allows the prefix and URI to be computed at runtime from XPath expressions or attribute value templates.
+
+This is useful when generating XML that must carry specific namespace declarations, particularly when the namespace URI or prefix comes from the input data rather than being known statically.
+
+`xsl:namespace` must appear inside a content constructor for an element — either inside a literal result element or inside `xsl:element`. It must precede any attribute or child nodes of that element.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:string (AVT) | Yes | The namespace prefix to bind. Use an empty string or `#default` for the default namespace. |
+| `select` | XPath expression | No | Expression evaluating to the namespace URI string. |
+
+If `select` is omitted, the content of `xsl:namespace` is used as the namespace URI.
+
+## Return value
+
+A namespace node is added to the result element. No content is added to the output tree.
+
+## Examples
+
+### Adding a dynamic namespace declaration
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+```
+
+### Setting a computed default namespace
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- If a namespace node for the same prefix already exists on the element with a different URI, a dynamic error is raised.
+- The empty string as `name` creates or changes the default namespace (equivalent to `xmlns="..."`).
+- `xsl:namespace` can only be used inside an element constructor; using it at the top level or after child elements is an error.
+- In many cases, namespace declarations propagate automatically. `xsl:namespace` is needed only when the prefix or URI must be determined from data.
+
+## See also
+
+- [xsl:element](../xsl-element)
+- [xsl:attribute](../xsl-attribute)
+- [xsl:import-schema](../xsl-import-schema)
diff --git a/site/content/xslt/functions/xsl-next-iteration.md b/site/content/xslt/functions/xsl-next-iteration.md
new file mode 100644
index 00000000..c25ad460
--- /dev/null
+++ b/site/content/xslt/functions/xsl-next-iteration.md
@@ -0,0 +1,115 @@
+---
+title: "xsl:next-iteration"
+description: "Advances an xsl:iterate loop to the next item in the sequence, optionally updating loop parameters to carry state forward."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: " "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:next-iteration` is the instruction that passes control to the next iteration of an `xsl:iterate` loop, carrying updated values for one or more loop parameters. It is the XSLT 3.0 equivalent of the tail-recursive call in a recursive named template, but expressed as a readable inline instruction.
+
+Each `xsl:iterate` loop can declare parameters with `xsl:param`. These parameters act as mutable state: their values change with each iteration via `xsl:next-iteration`. Without `xsl:next-iteration`, you cannot update loop parameters — the only other way out of an iteration body is to fall through to the end (which implicitly continues with unchanged parameters) or to execute `xsl:break`.
+
+`xsl:next-iteration` must be a direct child of the `xsl:iterate` body (not nested inside a template called from the iterate). It can appear inside `xsl:if`, `xsl:choose`, or `xsl:when`. Each `xsl:with-param` child names a parameter declared on the `xsl:iterate` and provides its new value. Parameters not mentioned retain their current value.
+
+When `xsl:next-iteration` executes, the current iteration body stops and the loop advances to the next item with the updated parameter values.
+
+## Attributes
+
+`xsl:next-iteration` has no element-specific attributes. It contains `xsl:with-param` children.
+
+## Examples
+
+### Running sum with xsl:iterate
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+
+
+```
+
+### Tracking maximum value seen so far
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:next-iteration` must appear directly inside the body of `xsl:iterate`, not inside a called template or function.
+- If `xsl:next-iteration` is omitted in a branch, the iteration continues with all parameters at their current values.
+- `xsl:with-param` children must reference parameters declared on the enclosing `xsl:iterate`.
+- `xsl:next-iteration` and `xsl:break` are mutually exclusive exit points for a single execution path through the iteration body.
+
+## See also
+
+- [xsl:break](../xsl-break)
+- [xsl:iterate](../xsl-iterate)
diff --git a/site/content/xslt/functions/xsl-next-match.md b/site/content/xslt/functions/xsl-next-match.md
new file mode 100644
index 00000000..ad58056d
--- /dev/null
+++ b/site/content/xslt/functions/xsl-next-match.md
@@ -0,0 +1,111 @@
+---
+title: "xsl:next-match"
+description: "Applies the next-priority matching template rule for the current node, passing optional parameters and tunnel parameters."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: " "
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:next-match` fires the next template rule that would have matched the current node if the current template rule did not exist. It is the XSLT 2.0 successor to `xsl:apply-imports`, but works across all templates regardless of import precedence — not only imported ones.
+
+The "next" template is determined by priority order: templates are ranked by import precedence and then by specificity. `xsl:next-match` skips the currently executing template and invokes the one immediately below it in that ranking. If no further matching template exists, the built-in default rules apply.
+
+This enables clean decorator-style patterns: a high-priority template handles a special case and then delegates the bulk of processing to a more generic rule.
+
+## Parameters
+
+`xsl:next-match` has no attributes. It may contain:
+
+| Child element | Description |
+|---------------|-------------|
+| `xsl:with-param` | Passes a parameter to the next template. |
+| `xsl:fallback` | Fallback content for processors that do not support `xsl:next-match`. |
+
+## Return value
+
+The result produced by the next matching template rule, inserted into the current output.
+
+## Examples
+
+### Adding a wrapper around generic output
+
+**Input XML:**
+```xml
+
+
+ Important note.
+ Regular paragraph.
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+
+ Regular paragraph.
+
+```
+
+### Passing a parameter to the next template
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:next-match` differs from `xsl:apply-imports` in that it considers **all** lower-priority templates, not only those from imported stylesheets.
+- It may only be used inside a template rule (`xsl:template`). Using it inside `xsl:function` is an error.
+- If no further matching template exists, the built-in template rule for the node type applies (e.g., text nodes produce their string value, element nodes apply templates to children).
+- Tunnel parameters passed with `xsl:with-param tunnel="yes"` flow transparently through the entire call chain.
+
+## See also
+
+- [xsl:apply-imports](../xsl-apply-imports)
+- [xsl:apply-templates](../xsl-apply-templates)
+- [xsl:fallback](../xsl-fallback)
diff --git a/site/content/xslt/functions/xsl-non-matching-substring.md b/site/content/xslt/functions/xsl-non-matching-substring.md
new file mode 100644
index 00000000..1d5934bb
--- /dev/null
+++ b/site/content/xslt/functions/xsl-non-matching-substring.md
@@ -0,0 +1,110 @@
+---
+title: "xsl:non-matching-substring"
+description: "Defines the template body applied to each substring that does not match the regex inside xsl:analyze-string."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:non-matching-substring` is a child element of `xsl:analyze-string`. Its body is instantiated once for each portion of the analyzed string that falls between matches — the "gaps" around the matched substrings, including any leading or trailing text.
+
+The element has no attributes. Inside it, the context item (`.`) is the non-matching segment as a string. `regex-group()` is not meaningful here because no capture groups apply to unmatched text.
+
+Omitting `xsl:non-matching-substring` effectively discards all non-matching text from the output, which is useful when you only want to extract the matched parts.
+
+## Parameters
+
+`xsl:non-matching-substring` has no attributes. It contains a sequence constructor.
+
+## Return value
+
+The nodes or atomic values produced by the sequence constructor, contributed to the output of the enclosing `xsl:analyze-string`.
+
+## Examples
+
+### Extracting only the matched parts (discarding non-matches)
+
+**Input XML:**
+```xml
+
+Error at line 42: file not found. Warning at line 99: deprecated API.
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ [line 42]
+ [line 99]
+
+```
+
+### Preserving non-matching text alongside highlights
+
+**Input XML:**
+```xml
+
+Remember to call 555-1234 or 555-5678 if urgent.
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+Remember to call 555-1234 or 555-5678 if urgent.
+```
+
+## Notes
+
+- `xsl:non-matching-substring` is only valid as a direct child of `xsl:analyze-string`.
+- If the regex matches the entire string, `xsl:non-matching-substring` is never instantiated.
+- Leading text before the first match and trailing text after the last match are also treated as non-matching substrings.
+- The context item is a string; node-related functions like `name()` or `parent::` are not applicable here.
+
+## See also
+
+- [xsl:analyze-string](../xsl-analyze-string)
+- [xsl:matching-substring](../xsl-matching-substring)
+- [regex-group()](../xpath-regex-group)
diff --git a/site/content/xslt/functions/xsl-number.md b/site/content/xslt/functions/xsl-number.md
new file mode 100644
index 00000000..7dbe692b
--- /dev/null
+++ b/site/content/xslt/functions/xsl-number.md
@@ -0,0 +1,130 @@
+---
+title: "xsl:number"
+description: "Formats a number or automatically generates a sequence number based on the node's position in the document."
+date: 2026-04-19T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xpath", "xslt1"]
+---
+
+## Description
+
+`xsl:number` inserts a formatted number into the result tree. It operates in two modes: when a `value` attribute is given it simply formats that value; when `value` is absent it automatically computes the source node's position within the document hierarchy according to the `level`, `count`, and `from` attributes.
+
+The `level` attribute controls how the position is computed. `single` (default) counts preceding siblings that match the `count` pattern at the same level. `multiple` generates a compound number like `2.3.1` across nested levels. `any` counts all matching nodes anywhere in the document before the current node, regardless of nesting depth.
+
+The `format` attribute is a picture string where `1` produces Arabic numerals, `a` lowercase letters, `A` uppercase letters, `i` lowercase Roman numerals, and `I` uppercase Roman numerals. Separator characters between tokens in the picture string are reproduced literally.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `value` | expression | No | Numeric expression to format. When present, `level`, `count`, and `from` are ignored. |
+| `level` | `single`, `multiple`, or `any` | No | Determines which nodes are counted (default `single`). |
+| `count` | pattern | No | Pattern identifying nodes to count. Defaults to nodes with the same name as the current node. |
+| `from` | pattern | No | Counting restarts at each node matching this pattern. |
+| `format` | string | No | Picture string controlling output format (default `1`). |
+| `lang` | NMTOKEN | No | Language used for alphabetic numbering. |
+| `letter-value` | `alphabetic` or `traditional` | No | Disambiguates numbering schemes where both exist. |
+| `grouping-separator` | char | No | Separator character for digit groups (e.g., `,`). |
+| `grouping-size` | number | No | Number of digits per group (e.g., `3`). |
+
+## Return value
+
+Inserts a formatted number string as a text node in the result tree.
+
+## Examples
+
+### Automatic chapter and section numbering
+
+**Input XML:**
+```xml
+
+
+ Introduction
+
+
+
+ Methods
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+ .
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+1. Introduction
+ 1.1 Background
+ 1.2 Scope
+2. Methods
+ 2.1 Data Collection
+```
+
+### Formatting an explicit value with grouping
+
+**Input XML:**
+```xml
+
+
+ 1234567
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+1,234,567
+```
+
+## Notes
+
+- When `value` is absent and no `count` pattern is specified, the processor defaults to counting nodes with the same expanded name as the current node.
+- `level="any"` is useful for footnote numbering that must be continuous across the whole document.
+- In XSLT 2.0 and later, `xsl:number` is largely unchanged but the processor may support additional `format` tokens for other scripts via the `lang` attribute.
+- `xsl:number` always inserts a text node; it cannot be used inside an attribute value template directly.
+
+## See also
+
+- [xsl:for-each](../xsl-for-each)
+- [format-number()](../xpath-format-number)
+- [xsl:decimal-format](../xsl-decimal-format)
+- [position()](../xpath-position)
diff --git a/site/content/xslt/functions/xsl-on-empty.md b/site/content/xslt/functions/xsl-on-empty.md
new file mode 100644
index 00000000..c25f9cdd
--- /dev/null
+++ b/site/content/xslt/functions/xsl-on-empty.md
@@ -0,0 +1,105 @@
+---
+title: "xsl:on-empty"
+description: "Generates fallback content when the sibling sequence constructor produces no nodes, enabling clean empty-state handling without extra variables."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: "... "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:on-empty` solves a recurring XSLT problem: how do you output something meaningful when a query returns no results? Before XSLT 3.0 you had to bind the result to a variable, test whether the variable was empty, and then branch with `xsl:choose`. `xsl:on-empty` eliminates this boilerplate by acting as an inline fallback within the same sequence of instructions.
+
+The element is evaluated *after* all preceding siblings in the same sequence constructor have been evaluated. If those siblings produced no nodes at all — not even whitespace-only text nodes — then the content of `xsl:on-empty` is output instead. If any node was produced, `xsl:on-empty` is silently skipped.
+
+This is particularly useful in streaming contexts where you cannot look ahead to know whether content exists before committing to write a wrapper element. Paired with `xsl:on-non-empty` and `xsl:where-populated`, these three elements form a trio for conditional-content control in XSLT 3.0.
+
+## Attributes
+
+`xsl:on-empty` has no element-specific attributes. It contains a sequence constructor.
+
+## Examples
+
+### Empty list fallback
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+ No books available.
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+```
+
+### Conditional section with multiple content sources
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+ All clear — no warnings.
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:on-empty` looks only at nodes produced by preceding siblings in the *same* sequence constructor, not at the final result tree. Whitespace-only text nodes do count as content.
+- It is safe to use in streaming mode because it works with already-processed content.
+- Only one `xsl:on-empty` should appear per sequence constructor; having multiple is allowed but only the first may ever fire.
+- Do not confuse with testing `count(nodes) = 0` — `xsl:on-empty` avoids needing a variable binding altogether.
+
+## See also
+
+- [xsl:on-non-empty](../xsl-on-non-empty)
+- [xsl:where-populated](../xsl-where-populated)
diff --git a/site/content/xslt/functions/xsl-on-non-empty.md b/site/content/xslt/functions/xsl-on-non-empty.md
new file mode 100644
index 00000000..56646440
--- /dev/null
+++ b/site/content/xslt/functions/xsl-on-non-empty.md
@@ -0,0 +1,110 @@
+---
+title: "xsl:on-non-empty"
+description: "Generates content only when the sibling sequence constructor produces at least one node, allowing conditional headers or wrappers without extra variables."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: "... "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:on-non-empty` is the complement of `xsl:on-empty`. Its content is output only when the other instructions in the same sequence constructor have produced at least one node. If no nodes were produced, `xsl:on-non-empty` is silently suppressed.
+
+The classic use case is a conditional heading or section wrapper that should only appear when there is actual content beneath it. Before XSLT 3.0 this required storing the content in a variable, testing whether it was non-empty, and then wrapping it — three steps. With `xsl:on-non-empty` you can express the heading inline, adjacent to the content that conditions it.
+
+Like `xsl:on-empty`, this element is evaluated after its preceding siblings in the same sequence constructor have been processed. It considers any node — including whitespace text nodes — as "non-empty" content.
+
+The three streaming-content elements (`xsl:on-empty`, `xsl:on-non-empty`, and `xsl:where-populated`) are often used together. `xsl:on-non-empty` belongs at the *start* of a sequence when the conditional content (such as a heading) must appear *before* the main content it guards.
+
+## Attributes
+
+`xsl:on-non-empty` has no element-specific attributes. It contains a sequence constructor.
+
+## Examples
+
+### Conditional section header before content
+
+**Input XML:**
+```xml
+
+
+
+ Disk quota exceeded
+ Network timeout
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+ Errors found
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+
Errors found
+
Disk quota exceeded
+
Network timeout
+
+```
+
+### Combined on-non-empty and on-empty
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ Items in stock:
+
+
+
+ No items currently in stock.
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:on-non-empty` must be evaluated by the processor after the preceding siblings. Processors that buffer content do so internally; the order in the output is still as written.
+- Like `xsl:on-empty`, it evaluates the *preceding sibling* nodes in the same sequence constructor only — not the wider result tree.
+- This element is streamable and works well inside streaming templates.
+- Whitespace-only text nodes produced by sibling instructions are counted as non-empty content.
+
+## See also
+
+- [xsl:on-empty](../xsl-on-empty)
+- [xsl:where-populated](../xsl-where-populated)
diff --git a/site/content/xslt/functions/xsl-otherwise.md b/site/content/xslt/functions/xsl-otherwise.md
new file mode 100644
index 00000000..044e4fe0
--- /dev/null
+++ b/site/content/xslt/functions/xsl-otherwise.md
@@ -0,0 +1,124 @@
+---
+title: "xsl:otherwise"
+description: "Default fallback branch inside xsl:choose, instantiated when no xsl:when condition evaluates to true."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:otherwise` is the optional final child of `xsl:choose` and acts as the default branch — the fallback when none of the preceding `xsl:when` conditions matched. Its content is instantiated exactly when all sibling `xsl:when` tests evaluate to false.
+
+If `xsl:otherwise` is absent and no `xsl:when` matches, the `xsl:choose` element produces no output and raises no error. Adding `xsl:otherwise` is therefore a defensive practice: it lets you handle unexpected values explicitly rather than silently producing empty output.
+
+An `xsl:choose` may contain at most one `xsl:otherwise`, and it must appear after all `xsl:when` siblings. It takes no attributes.
+
+## Attributes
+
+`xsl:otherwise` has no attributes. Its entire behavior is expressed through its content.
+
+## Examples
+
+### Unknown value handling
+
+**Input XML:**
+```xml
+
+
+ Button pressed
+ Input focused
+ Something else
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ user-action
+
+
+ ui-event
+
+
+ unknown
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ user-action Button pressed
+ ui-event Input focused
+ unknown custom Something else
+
+```
+
+### Error signaling with xsl:message
+
+**Input XML:**
+```xml
+
+production
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+ PROD
+ STG
+ DEV
+
+
+ Unknown mode:
+
+
+
+
+
+
+```
+
+**Output:**
+```
+PROD
+```
+
+## Notes
+
+- Placing `xsl:otherwise` before any `xsl:when` is a schema validation error and most processors will reject it.
+- An `xsl:otherwise` with no content is valid and simply produces no output — this can be used intentionally to suppress output for unrecognised values without raising an error.
+- `xsl:otherwise` has no test attribute; if you need a final condition rather than an unconditional default, add another `xsl:when` before it.
+
+## See also
+
+- [xsl:choose](../xsl-choose)
+- [xsl:when](../xsl-when)
+- [xsl:if](../xsl-if)
diff --git a/site/content/xslt/functions/xsl-output-character.md b/site/content/xslt/functions/xsl-output-character.md
new file mode 100644
index 00000000..44ff26d0
--- /dev/null
+++ b/site/content/xslt/functions/xsl-output-character.md
@@ -0,0 +1,93 @@
+---
+title: "xsl:output-character"
+description: "Specifies a single character-to-string substitution within an xsl:character-map, applied by the serializer when writing output."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:output-character` is a child element of `xsl:character-map`. It maps a single Unicode character to a replacement string that the serializer writes literally in the output — bypassing normal XML escaping. Each `xsl:output-character` handles exactly one character.
+
+The `character` attribute must be a single XML character (specified as a literal character or a character reference such as ` `). The `string` attribute is the text string written to the output in its place — including any markup or entity references you want to appear literally.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `character` | Single XML character | Yes | The Unicode character to intercept during serialization. |
+| `string` | xs:string | Yes | The string to write in place of the character. |
+
+## Return value
+
+No output. This declaration is used only by the serializer when the enclosing `xsl:character-map` is active.
+
+## Examples
+
+### Common HTML entity mappings
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+If the input contains `©` (U+00A9) and `—` (U+2014), the output will contain `©` and `—` literally.
+
+### Escaping special characters for legacy systems
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Input text:** `He said “hello” and she replied ‘hi’.`
+**Output text:** `He said "hello" and she replied 'hi'.`
+
+## Notes
+
+- The `character` attribute must contain exactly one XML character. Strings are not supported; use one `xsl:output-character` per character.
+- The `string` attribute value is written verbatim. If it contains characters that would normally be escaped by the serializer, the character map takes precedence.
+- A character can appear in only one `xsl:output-character` within the combined set of active character maps.
+- This element has no effect on the internal XDM tree; it only affects the serialized text output.
+
+## See also
+
+- [xsl:character-map](../xsl-character-map)
+- [xsl:output](../xsl-output)
diff --git a/site/content/xslt/functions/xsl-output.md b/site/content/xslt/functions/xsl-output.md
new file mode 100644
index 00000000..4daed445
--- /dev/null
+++ b/site/content/xslt/functions/xsl-output.md
@@ -0,0 +1,117 @@
+---
+title: "xsl:output"
+description: "Controls how the result tree is serialised — output method, encoding, indentation, DOCTYPE, and other serialisation options."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:output` is a top-level declaration that controls the serialisation of the result tree — how the abstract tree of nodes is converted to a stream of characters or bytes. It does not affect what nodes are in the result tree; it only affects how those nodes are written to the output.
+
+The three standard output methods are:
+
+- **`xml`** — Serialises as an XML document. Special characters are escaped, an XML declaration may be added, and the result is always well-formed XML.
+- **`html`** — Serialises following HTML conventions: void elements like ` ` are written without a closing tag, boolean attributes are written without values, and the `DOCTYPE` is added if specified.
+- **`text`** — Serialises only the string values of text nodes; all markup is omitted.
+
+Multiple `xsl:output` declarations in the same stylesheet are allowed and their attributes are merged. When the same attribute appears in multiple declarations, the one with the highest import precedence wins; within the same precedence level, the last declaration wins.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `method` | `xml` / `html` / `text` / QName | No | Serialisation method. Default is `xml` unless the root element is `html`. |
+| `version` | NMTOKEN | No | Version of the output format (e.g., `"4.0"` for HTML). |
+| `encoding` | encoding name | No | Character encoding (e.g., `"UTF-8"`, `"ISO-8859-1"`). |
+| `omit-xml-declaration` | `yes` / `no` | No | Whether to suppress the `` declaration. |
+| `standalone` | `yes` / `no` | No | Value of the `standalone` attribute in the XML declaration. |
+| `doctype-public` | string | No | Public identifier for the `DOCTYPE` declaration. |
+| `doctype-system` | string | No | System identifier for the `DOCTYPE` declaration. |
+| `cdata-section-elements` | whitespace-separated QNames | No | Elements whose text content should be serialised as CDATA sections. |
+| `indent` | `yes` / `no` | No | Whether to add whitespace indentation. |
+| `media-type` | MIME type | No | Media type of the output. |
+
+## Examples
+
+### XML output with indentation
+
+**Input XML:**
+```xml
+
+- A
- B
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+ - A
+ - B
+
+```
+
+### HTML output with DOCTYPE
+
+**Input XML:**
+```xml
+
+Hello World
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+
+Hello
+World
+
+```
+
+## Notes
+
+- `xsl:output` is advisory: a processor is not required to serialise the result at all (it may hand the result tree to a further processing step). When serialisation does occur, the processor should honour the settings.
+- `indent="yes"` may add whitespace-only text nodes to the output. This can cause problems if the consuming application is whitespace-sensitive; use it only for human-readable output.
+- `cdata-section-elements` is useful for elements containing JavaScript or CSS in HTML, where `<`, `>`, and `&` should not be escaped.
+- In XSLT 2.0+, `xsl:output` gains additional attributes including `use-character-maps`, `normalization-form`, `undeclare-prefixes`, and `html-version`.
+
+## See also
+
+- [xsl:stylesheet](../xsl-stylesheet)
+- [xsl:text](../xsl-text)
diff --git a/site/content/xslt/functions/xsl-override.md b/site/content/xslt/functions/xsl-override.md
new file mode 100644
index 00000000..dba08c56
--- /dev/null
+++ b/site/content/xslt/functions/xsl-override.md
@@ -0,0 +1,137 @@
+---
+title: "xsl:override"
+description: "Inside xsl:use-package, provides local implementations that replace specific components imported from the used package."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:override` is a child element of `xsl:use-package` that contains one or more locally-defined component declarations—templates, functions, variables, or attribute sets—that replace components of the same name imported from the used package. It is the mechanism for customising or extending a package without modifying the package source.
+
+A component in the used package can be overridden only if its visibility is `public` or `abstract` (not `final` or `private`). When an override is provided for an `abstract` component, the local definition satisfies the package's requirement for an implementation. When an override is provided for a `public` component, the local definition takes precedence over the package's version.
+
+Within the overriding implementation, the original package component can be called using `xsl:original`, which refers to the superseded version, enabling a decorator pattern where local code augments rather than entirely replaces the original.
+
+## Parameters
+
+`xsl:override` takes no attributes. Its content is one or more component declarations (e.g., `xsl:template`, `xsl:function`, `xsl:variable`) whose names match components exposed as `public` or `abstract` by the used package.
+
+## Return value
+
+`xsl:override` is a declaration; it produces no XDM value.
+
+## Examples
+
+### Overriding a public function to change its behaviour
+
+Assume package `com.example.pricing` exposes a public function `pricing:apply-discount#2`.
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+```
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Output (original function applies 10% discount; override applies 20%):**
+```xml
+
+ - 80.00
+ - 160.00
+
+```
+
+### Implementing an abstract template required by a layout package
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+
+
+
+```
+
+## Notes
+
+- Only components with `public` or `abstract` visibility in the used package may appear inside `xsl:override`. Attempting to override a `final` or `private` component is a static error.
+- `xsl:original` is a pseudo-instruction available inside an overriding component that delegates to the original package implementation. It uses the same calling syntax as the normal call (e.g., `xsl:original` as a function call for functions, or ` ` for templates).
+- Overrides in `xsl:override` are not subject to import precedence; they unconditionally replace the package component.
+- A single `xsl:use-package` may contain at most one `xsl:override` element, but that element may contain multiple component declarations.
+
+## See also
+
+- [xsl:use-package](../xsl-use-package)
+- [xsl:accept](../xsl-accept)
diff --git a/site/content/xslt/functions/xsl-package.md b/site/content/xslt/functions/xsl-package.md
new file mode 100644
index 00000000..c639e246
--- /dev/null
+++ b/site/content/xslt/functions/xsl-package.md
@@ -0,0 +1,103 @@
+---
+title: "xsl:package"
+description: "The root element of an XSLT 3.0 package, a named and versioned reusable unit of stylesheet components."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:package` is the root element of a standalone XSLT 3.0 package — a named, versioned unit of XSLT logic that can be shared and reused across multiple stylesheets. Packages are the primary modularity mechanism in XSLT 3.0, superseding the `xsl:import` and `xsl:include` mechanisms for library authoring.
+
+A package has a URI name (the `name` attribute) and a version string (the `package-version` attribute). The `version` attribute specifies the XSLT version in use (always `3.0` for packages). Components within the package are `private` by default; use `xsl:expose` to make them accessible to consuming stylesheets.
+
+Packages can use other packages via `xsl:use-package`. A consuming stylesheet uses `xsl:use-package` to import the package and optionally overrides or re-exposes components.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | xs:anyURI | Yes | A URI that uniquely identifies the package. |
+| `package-version` | string | Yes | A version string for this package (e.g. `"1.0"` or `"2.3.1"`). |
+| `version` | string | Yes | XSLT version — must be `"3.0"` for packages. |
+| `id` | xs:ID | No | An optional XML ID for the package element. |
+| `input-type-annotations` | keyword | No | Controls type annotation stripping: `preserve`, `strip`, or `unspecified`. |
+
+## Return value
+
+`xsl:package` is a structural container; it produces no direct output.
+
+## Examples
+
+### A simple utility package
+
+**Package file (math-utils.xsl):**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Consuming the package
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 25
+ 27
+
+```
+
+## Notes
+
+- A package file uses `xsl:package` as its root element instead of `xsl:stylesheet` or `xsl:transform`. An `xsl:package` element may not have a named initial template that serves as the transformation entry point — it is a library, not a runnable transformation.
+- The `package-version` string follows no required format, but a dotted version scheme (e.g. `1.2.3`) is conventional and supported by version pattern matching in `xsl:use-package`.
+- Packages can use other packages, enabling layered library architectures.
+- Processor-specific configuration is needed to tell the processor where to find packages referenced by name.
+
+## See also
+
+- [xsl:use-package](../xsl-use-package)
+- [xsl:expose](../xsl-expose)
+- [xsl:accept](../xsl-accept)
+- [xsl:override](../xsl-override)
diff --git a/site/content/xslt/functions/xsl-param.md b/site/content/xslt/functions/xsl-param.md
new file mode 100644
index 00000000..a824f54c
--- /dev/null
+++ b/site/content/xslt/functions/xsl-param.md
@@ -0,0 +1,116 @@
+---
+title: "xsl:param"
+description: "Declares a parameter with an optional default value, accepting values passed via xsl:with-param or from the calling environment."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:param` declares a named parameter. It is syntactically similar to `xsl:variable`, but its value can be overridden by the caller at the point of invocation. If the caller does not supply a value, the default expressed by `select` or element content is used instead.
+
+Like `xsl:variable`, `xsl:param` can appear at two levels:
+
+- **Top-level** (direct child of `xsl:stylesheet`): declares a global stylesheet parameter. XSLT processors typically allow the host environment (a Java application, a command-line tool, or a browser) to supply values for top-level parameters at runtime.
+- **Inside `xsl:template`**: declares a template parameter. The value is supplied by `xsl:with-param` in the calling `xsl:apply-templates` or `xsl:call-template`.
+
+Once set for a given invocation, a parameter is immutable — you cannot reassign it inside the template body, just as with `xsl:variable`.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | The parameter name, referenced as `$name` in XPath. |
+| `select` | XPath expression | No | Default value expression. Used when caller does not provide a value. |
+| `as` | SequenceType | No | (2.0+) Expected type for type-checking. |
+| `required` | `yes` / `no` | No | (2.0+) If `yes`, raises an error when no value is passed. Default `no`. |
+| `tunnel` | `yes` / `no` | No | (2.0+) Tunnel parameters bypass intermediate templates automatically. |
+
+## Examples
+
+### Template parameter with default
+
+**Input XML:**
+```xml
+
+Hello
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+ World
+
+
+
+
+
+
+ Saxon
+
+
+
+```
+
+**Output:**
+```
+Hi, Saxon!
+```
+
+### Top-level stylesheet parameter
+
+**Input XML:**
+```xml
+
+1500
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+ USD
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output** (with default parameters):
+```xml
+
+ 1,500.00 USD
+
+```
+
+## Notes
+
+- A template parameter that is not passed by the caller silently uses its default value. In XSLT 1.0, there is no way to make a parameter required at the language level; you must check with `xsl:if` and emit `xsl:message` if needed.
+- `xsl:param` must appear before any other instructions in a template body; placing it after variable declarations or output instructions is an error.
+- Global parameters supplied by the host environment are typically strings. Numeric or node-set values may require explicit conversion in the stylesheet.
+- In XSLT 2.0+, the `required="yes"` attribute provides a first-class mechanism for mandatory parameters, removing the need for manual guard checks.
+
+## See also
+
+- [xsl:variable](../xsl-variable)
+- [xsl:with-param](../xsl-with-param)
+- [xsl:call-template](../xsl-call-template)
+- [xsl:apply-templates](../xsl-apply-templates)
diff --git a/site/content/xslt/functions/xsl-perform-sort.md b/site/content/xslt/functions/xsl-perform-sort.md
new file mode 100644
index 00000000..071e6818
--- /dev/null
+++ b/site/content/xslt/functions/xsl-perform-sort.md
@@ -0,0 +1,116 @@
+---
+title: "xsl:perform-sort"
+description: "Sorts a sequence of items and returns the sorted sequence without iterating over it, enabling sorted results as input to other expressions."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:perform-sort` sorts a sequence and produces the sorted sequence as its result. Unlike `xsl:for-each` with `xsl:sort`, it does not iterate — it simply reorders. The sorted sequence can be assigned to a variable, passed to a function, or used in any context that accepts a sequence.
+
+This is particularly useful when you need to sort data and then use the sorted result in a further expression, such as selecting the top-N items or building a lookup.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | XPath expression | No | The sequence to sort. If omitted, the content of `xsl:perform-sort` defines the sequence via `xsl:sequence`. |
+
+It must contain one or more `xsl:sort` children that define the sort keys.
+
+## Return value
+
+The items from the input sequence reordered according to the `xsl:sort` specifications.
+
+## Examples
+
+### Sorting and taking the top 3
+
+**Input XML:**
+```xml
+
+
+ 87
+ 95
+ 72
+ 95
+ 81
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+
+```
+
+### Sorting inside a function
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- `xsl:perform-sort` is not an iterator. To process each sorted item, wrap it in `xsl:for-each` or assign it to a variable.
+- When `select` is omitted, the body must produce the sequence to sort using `xsl:sequence`.
+- Multiple `xsl:sort` children are allowed; they define primary, secondary, and further sort keys in order.
+- Sort stability: if two items compare equal on all keys, their relative order from the input is preserved (stable sort).
+
+## See also
+
+- [xsl:for-each](../xsl-for-each)
+- [xsl:sort](../xsl-sort)
+- [xsl:for-each-group](../xsl-for-each-group)
diff --git a/site/content/xslt/functions/xsl-preserve-space.md b/site/content/xslt/functions/xsl-preserve-space.md
new file mode 100644
index 00000000..366be900
--- /dev/null
+++ b/site/content/xslt/functions/xsl-preserve-space.md
@@ -0,0 +1,113 @@
+---
+title: "xsl:preserve-space"
+description: "Explicitly preserves whitespace-only text nodes in the named source elements, counteracting xsl:strip-space rules."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:preserve-space` is a top-level declaration that instructs the XSLT processor to keep whitespace-only text nodes in the specified source elements when building the source tree. By default, without any whitespace directives, all whitespace-only text nodes in the source document are preserved.
+
+Its primary use is as an exception to `xsl:strip-space`. When a stylesheet has a broad `xsl:strip-space elements="*"` rule that removes all whitespace-only text nodes, `xsl:preserve-space` can carve out specific elements where whitespace is significant and must not be touched.
+
+The `elements` attribute takes a whitespace-separated list of element names or the wildcard `*`. Element names may be namespace-qualified. Import precedence applies: if `xsl:strip-space` and `xsl:preserve-space` both match the same element at the same import precedence, a conflict error is raised.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `elements` | whitespace-separated NameTests | Yes | Elements in which whitespace-only text nodes should be preserved. Use `*` for all elements. |
+
+## Examples
+
+### Preserving whitespace in code blocks
+
+**Input XML:**
+```xml
+
+
+ This paragraph has leading spaces.
+
+ line one
+ line two
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+This paragraph has leading spaces.
+ line one
+ line two
+
+```
+
+### Selective preservation in a mixed document
+
+**Input XML:**
+```xml
+
+
+ spaced
+ preserved
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ spaced
+ preserved
+
+```
+
+## Notes
+
+- `xsl:preserve-space` only affects **whitespace-only** text nodes in source elements. Text nodes that contain non-whitespace characters are never stripped regardless of any directive.
+- The `xml:space="preserve"` attribute in the source document also prevents stripping, regardless of `xsl:strip-space` directives.
+- These directives affect the source tree built from the primary input document and from documents loaded with the `document()` function.
+- Whitespace stripping happens before pattern matching; it does not remove whitespace-only text nodes from the result tree.
+
+## See also
+
+- [xsl:strip-space](../xsl-strip-space)
+- [xsl:output](../xsl-output)
diff --git a/site/content/xslt/functions/xsl-processing-instruction.md b/site/content/xslt/functions/xsl-processing-instruction.md
new file mode 100644
index 00000000..3bfb3df7
--- /dev/null
+++ b/site/content/xslt/functions/xsl-processing-instruction.md
@@ -0,0 +1,114 @@
+---
+title: "xsl:processing-instruction"
+description: "Generates an XML processing instruction in the result tree with a computed name and body content."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:processing-instruction` inserts a processing instruction (PI) node into the result tree. A processing instruction has the form ``, where `target` is the PI name and `data` is the optional text body.
+
+Processing instructions are used to embed application-specific directives inside XML documents. Common examples include `` for attaching stylesheets, `` for PHP code, and `` for schema association. In XSLT transformations, they are typically used to produce these directives programmatically based on source data.
+
+The `name` attribute is an attribute value template, so the PI target name can be computed. The content of `xsl:processing-instruction` produces the data portion of the PI as a string; it may include `xsl:value-of`, `xsl:text`, and variables.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | AVT (NCName) | Yes | The processing instruction target name. Must be a valid XML NCName and must not be `xml` (case-insensitive). |
+
+## Examples
+
+### Adding an xml-stylesheet PI
+
+**Input XML:**
+```xml
+
+
+ Manual
+ Guide
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+ href="
+
+ .css" type="text/css"
+
+
+
+
+```
+
+**Output:**
+```xml
+
+Manual
+
+Guide
+```
+
+### Computed PI name from source data
+
+**Input XML:**
+```xml
+
+
+ echo "hello";
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+```
+
+## Notes
+
+- The PI name must not be `xml` or `XML` in any capitalisation — this is reserved by the XML specification. Processors must reject it with an error.
+- The data portion of the PI must not contain `?>`, as that would prematurely end the PI. If generated content might include this sequence, guard against it or transform the input.
+- When the output method is `text`, processing instructions are silently omitted.
+- PIs are not visible in rendered HTML, but they appear in the raw source and are accessible via the DOM in browsers.
+
+## See also
+
+- [xsl:comment](../xsl-comment)
+- [xsl:output](../xsl-output)
+- [xsl:text](../xsl-text)
diff --git a/site/content/xslt/functions/xsl-result-document.md b/site/content/xslt/functions/xsl-result-document.md
new file mode 100644
index 00000000..b24c2910
--- /dev/null
+++ b/site/content/xslt/functions/xsl-result-document.md
@@ -0,0 +1,127 @@
+---
+title: "xsl:result-document"
+description: "Writes transformation output to a secondary result document at a specified URI, enabling a single stylesheet to produce multiple output files."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:result-document` creates a secondary result tree and writes it to a URI. The primary output of the transformation is produced normally; `xsl:result-document` adds one or more additional outputs. This is the XSLT 2.0 mechanism for splitting a single input document into multiple output files — for example, generating one HTML page per chapter of a book.
+
+The `href` attribute names the destination URI. Relative URIs are resolved against the base output URI supplied by the calling application. If `href` is omitted, the instruction writes to the principal result tree (useful to override serialization settings for a section of output).
+
+All serialization attributes available on `xsl:output` may also appear directly on `xsl:result-document` and override the named output format for that specific document.
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `href` | URI (AVT) | No | Destination URI for the secondary document. |
+| `format` | QName | No | Named output format (refers to an `xsl:output` name attribute). |
+| `method` | `xml` \| `html` \| `text` \| `xhtml` | No | Serialization method. |
+| `indent` | `yes` \| `no` | No | Whether to add indentation. |
+| `encoding` | string | No | Character encoding, e.g. `UTF-8`. |
+| `doctype-public` | string | No | DOCTYPE public identifier. |
+| `doctype-system` | string | No | DOCTYPE system identifier. |
+| `omit-xml-declaration` | `yes` \| `no` | No | Suppress the XML declaration. |
+| `use-character-maps` | QNames | No | Apply named character maps on output. |
+
+## Return value
+
+Nothing is added to the current result tree. The content produced inside the element body is written to the secondary document.
+
+## Examples
+
+### Splitting chapters into separate files
+
+**Input XML:**
+```xml
+
+
+ Content of chapter 1.
+ Content of chapter 2.
+ Content of chapter 3.
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Back
+
+
+
+
+
+
+```
+
+**Files produced:** `index.html`, `ch1.html`, `ch2.html`, `ch3.html`.
+
+### Writing a plain-text log alongside XML output
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Saxon supports `xsl:result-document` in both file-system and in-memory scenarios. In some processors (e.g., browser-based), writing to a file URI may not be permitted.
+- `href` is an attribute value template (AVT), so dynamic URIs like `{@id}.html` are fully supported.
+- Result documents must be **serialized independently**; they cannot reference nodes in other result documents.
+- Nesting `xsl:result-document` inside another `xsl:result-document` is allowed and creates further secondary documents.
+- In Saxon-EE, result documents can be written in parallel for performance.
+
+## See also
+
+- [xsl:output](../xsl-output)
+- [xsl:sequence](../xsl-sequence)
+- [xsl:character-map](../xsl-character-map)
diff --git a/site/content/xslt/functions/xsl-sequence.md b/site/content/xslt/functions/xsl-sequence.md
new file mode 100644
index 00000000..519a2b2e
--- /dev/null
+++ b/site/content/xslt/functions/xsl-sequence.md
@@ -0,0 +1,121 @@
+---
+title: "xsl:sequence"
+description: "Returns a sequence of items; the XSLT 2.0 equivalent of xsl:value-of for typed values and node sequences."
+date: 2026-04-18T00:00:00Z
+version: "2.0"
+versionLabel: "XSLT 2.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt2"]
+---
+
+## Description
+
+`xsl:sequence` evaluates an XPath expression and adds the resulting items — nodes, atomic values, or mixed sequences — directly to the result sequence of the current template or function. Unlike `xsl:value-of`, it preserves the type of each item: integers stay integers, nodes stay nodes, and sequences remain sequences.
+
+It is the idiomatic way to return a value from an `xsl:function`, and the correct instruction to use when you want to pass typed data rather than a string representation.
+
+Key differences from `xsl:value-of`:
+
+| | `xsl:value-of` | `xsl:sequence` |
+|---|---|---|
+| Output | Always a text node | Items of any type |
+| Types preserved | No (stringified) | Yes |
+| Nodes | Copies as text | Adds as reference or copy |
+
+## Parameters
+
+| Parameter | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | XPath expression | Yes | The expression whose result is added to the output sequence. |
+
+## Return value
+
+The items produced by the `select` expression, added to the current output sequence. No wrapper node is created.
+
+## Examples
+
+### Returning a typed value from a function
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+42
+```
+
+### Returning a node sequence
+
+**Input XML:**
+```xml
+
+
+ - Alpha
+ - Beta
+ - Gamma
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alpha
+ Gamma
+
+```
+
+## Notes
+
+- `xsl:sequence` is the only correct way to return typed values (integers, dates, booleans) from `xsl:function`. Using `xsl:value-of` inside a function always produces a text node.
+- When `select` returns nodes, they are added by reference to the sequence, not deep-copied. If you need independent copies, wrap with `copy-of()`.
+- `xsl:sequence` can appear in any context where items are allowed, including inside `xsl:choose`, `xsl:if`, and `xsl:for-each`.
+- An empty `xsl:sequence select="()"` adds nothing — useful as a no-op branch in a conditional.
+
+## See also
+
+- [xsl:value-of](../xsl-value-of)
+- [xsl:result-document](../xsl-result-document)
+- [xsl:function](../xsl-function)
diff --git a/site/content/xslt/functions/xsl-sort.md b/site/content/xslt/functions/xsl-sort.md
new file mode 100644
index 00000000..e89d20af
--- /dev/null
+++ b/site/content/xslt/functions/xsl-sort.md
@@ -0,0 +1,127 @@
+---
+title: "xsl:sort"
+description: "Specifies a sort key for xsl:apply-templates or xsl:for-each, controlling the order in which nodes are processed."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:sort` is placed as an immediate child of `xsl:apply-templates` or `xsl:for-each` to define the sort order for node processing. It does not alter the source document; it only changes the sequence in which the processor visits the selected nodes.
+
+Multiple `xsl:sort` elements can be nested to define compound sort keys: the first `xsl:sort` is the primary key, the second is the secondary key (used when the primary values are equal), and so on.
+
+The `select` attribute is an XPath expression evaluated against each candidate node to produce its sort key. Omitting `select` defaults to the string value of the context node (equivalent to `select="."`). The `data-type` attribute controls whether comparison is lexicographic (`text`, the default) or numeric (`number`). When sorting numerically, the key is converted to a number; non-numeric strings sort as `NaN`, which typically appears first in ascending order.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | XPath expression | No | Sort key expression. Defaults to `.` (string value of context node). |
+| `order` | `ascending` / `descending` | No | Sort direction. Default is `ascending`. |
+| `data-type` | `text` / `number` / QName | No | Comparison type. Default is `text`. |
+| `case-order` | `upper-first` / `lower-first` | No | Case ordering for text comparisons. Processor-defined default. |
+| `lang` | language code | No | Language for locale-sensitive collation. |
+
+## Examples
+
+### Sort by numeric attribute
+
+**Input XML:**
+```xml
+
+
+ Gadget
+ Widget
+ Device
+ Bolt
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Bolt
+ - Widget
+ - Gadget
+ - Device
+
+```
+
+### Multi-key sort: last name then first name
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Bob Jones
+ Carol Jones
+ Alice Smith
+ Anna Smith
+
+```
+
+## Notes
+
+- `xsl:sort` elements must appear before any other content inside `xsl:for-each` or `xsl:apply-templates`. Placing them after output instructions is a schema error.
+- When `data-type="number"`, the sort key is converted to a floating-point number. Values that cannot be converted become `NaN`; in ascending order, `NaN` values typically sort before any numeric value, but this is implementation-defined.
+- Text sorting is locale-sensitive in theory, but XSLT 1.0 has limited collation support. Use the `lang` attribute or processor-specific collation URIs for reliable locale-aware sorting.
+- The `position()` function inside a sorted `xsl:for-each` reflects the sorted position, not the original document position.
+
+## See also
+
+- [xsl:for-each](../xsl-for-each)
+- [xsl:apply-templates](../xsl-apply-templates)
+- [xsl:number](../xsl-number)
diff --git a/site/content/xslt/functions/xsl-stream.md b/site/content/xslt/functions/xsl-stream.md
new file mode 100644
index 00000000..43751e49
--- /dev/null
+++ b/site/content/xslt/functions/xsl-stream.md
@@ -0,0 +1,101 @@
+---
+title: "xsl:stream"
+description: "Processes a source document in streaming mode without loading it fully into memory, enabling transformation of arbitrarily large XML files."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: '... '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:stream` is the gateway to XSLT 3.0 streaming. Instead of loading the entire source document into memory as a tree, the processor reads it as a sequential stream of events (similar to SAX). This makes it possible to process XML files of any size — gigabytes of log data, large export files, huge datasets — without running out of memory.
+
+The `href` attribute specifies the URI of the document to stream. The content of `xsl:stream` is a sequence constructor that is evaluated in streaming mode. The context item within the constructor is the document node of the streamed document.
+
+Streaming imposes important restrictions. You can only make *one downward pass* through each node. You cannot navigate upward (to the parent or document node after descending) or reference a node more than once. Templates called from within a streaming context must themselves be streamable. `xsl:accumulator` is the primary mechanism for gathering state as nodes stream past.
+
+`xsl:stream` is a top-level instruction typically placed inside a template matching `/` or invoked from an initial template. It is supported by processors that declare streaming support (Saxon EE, for example). Processors that do not support streaming treat `xsl:stream` as an error unless the `[XTSE3430]` fallback is handled.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `href` | URI | Yes | The URI of the document to process in streaming mode. |
+
+## Examples
+
+### Count elements in a large document without loading it
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Streaming with an accumulator to track totals
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- Streaming requires processor support; not all XSLT 3.0 processors implement it. Saxon EE supports full streaming.
+- Within `xsl:stream`, expressions must follow streamability rules: no upward axes after descending, no multiple passes over a node.
+- Use `xsl:fork` inside `xsl:stream` to process the stream in multiple independent branches in a single pass.
+- `xsl:stream` cannot appear inside a template or function — it must be a direct call from an initial template or a template with a streaming-compatible context.
+
+## See also
+
+- [xsl:fork](../xsl-fork)
+- [xsl:merge](../xsl-merge)
+- [xsl:accumulator](../xsl-accumulator)
diff --git a/site/content/xslt/functions/xsl-strip-space.md b/site/content/xslt/functions/xsl-strip-space.md
new file mode 100644
index 00000000..0db92ef6
--- /dev/null
+++ b/site/content/xslt/functions/xsl-strip-space.md
@@ -0,0 +1,133 @@
+---
+title: "xsl:strip-space"
+description: "Removes whitespace-only text nodes from the specified source elements before the transformation begins processing them."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:strip-space` instructs the XSLT processor to discard text nodes that consist entirely of whitespace characters from the specified source elements. This affects the source tree built before any templates run; stripped nodes are never seen by the transformation.
+
+The most common form is ` `, which removes all whitespace-only text nodes from every element in the source document. This is useful when the source XML was indented for human readability and the whitespace carries no meaning — the strip rule prevents these invisible text nodes from appearing in `position()` counts, triggering built-in text templates, or otherwise interfering with the transformation.
+
+The `elements` attribute accepts a whitespace-separated list of element name tests or the wildcard `*`. `xsl:preserve-space` can override `xsl:strip-space` for specific elements where whitespace is significant.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `elements` | whitespace-separated NameTests | Yes | Elements from which whitespace-only text nodes are removed. Use `*` for all. |
+
+## Examples
+
+### Stripping indentation whitespace
+
+**Input XML:**
+```xml
+
+
+
+
+```
+
+**Stylesheet without strip-space** (produces extra whitespace text nodes):
+```xml
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+```
+
+**Stylesheet with strip-space** (clean numbering):
+```xml
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+```
+
+**Output:**
+```
+1: Soup
+2: Salad
+```
+
+### Selective stripping
+
+**Input XML:**
+```xml
+
+
+ Total: 5
+
+ - A
+ - B
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Total: 5
+
+ - A
+ - B
+
+
+```
+
+## Notes
+
+- Stripping only removes text nodes that are **entirely** whitespace. Mixed-content text nodes containing non-whitespace characters are never affected.
+- The `xml:space="preserve"` attribute in the source document prevents stripping for that element and all its descendants, even if `xsl:strip-space` targets them.
+- Whitespace stripping is applied after the XML parser builds the source tree, before any template processing starts. It cannot be applied conditionally during transformation.
+- When `xsl:strip-space elements="*"` and `xsl:preserve-space elements="pre"` are both present, `xsl:preserve-space` wins for `pre` elements because it is more specific.
+
+## See also
+
+- [xsl:preserve-space](../xsl-preserve-space)
+- [xsl:output](../xsl-output)
diff --git a/site/content/xslt/functions/xsl-stylesheet.md b/site/content/xslt/functions/xsl-stylesheet.md
new file mode 100644
index 00000000..89b2bee1
--- /dev/null
+++ b/site/content/xslt/functions/xsl-stylesheet.md
@@ -0,0 +1,108 @@
+---
+title: "xsl:stylesheet"
+description: "Root element of every XSLT stylesheet, declaring the version, namespace, and top-level declarations for the transformation."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:stylesheet` is the mandatory root element of an XSLT stylesheet document. It binds the XSLT namespace, declares the language version, and acts as the container for all top-level declarations such as templates, variables, parameters, keys, and output settings.
+
+The `version` attribute is required and tells the processor which version of the XSLT specification governs this stylesheet. Setting it to `"1.0"` requests strict XSLT 1.0 processing; a conforming XSLT 2.0 or 3.0 processor will then run in backwards-compatibility mode.
+
+The namespace declaration `xmlns:xsl="http://www.w3.org/1999/XSL/Transform"` must appear on this element (or be inherited by it) because every XSLT instruction element must be in that namespace. You may also declare additional namespaces here — for extension functions, output namespace prefixes, or the document's own vocabulary.
+
+`xsl:stylesheet` and `xsl:transform` are fully interchangeable synonyms; by convention most stylesheets use `xsl:stylesheet`.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `version` | `"1.0"` / `"2.0"` / `"3.0"` | Yes | XSLT version governing this stylesheet. |
+| `id` | ID | No | Unique identifier for the element. |
+| `extension-element-prefixes` | whitespace-separated prefixes | No | Namespace prefixes to treat as extension element prefixes rather than literal result elements. |
+| `exclude-result-prefixes` | whitespace-separated prefixes | No | Namespace prefixes that should not be copied into the result tree. |
+| `xpath-default-namespace` | URI | No | (2.0+) Default namespace for unprefixed XPath steps. |
+| `default-collation` | URI | No | (2.0+) Default collation for string comparisons. |
+| `input-type-annotations` | `strip` / `preserve` / `unspecified` | No | (2.0+) Whether schema type annotations on input nodes are retained. |
+
+## Examples
+
+### Minimal XSLT 1.0 stylesheet
+
+**Input XML:**
+```xml
+
+Hello, World!
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+Hello, World!
+```
+
+### Stylesheet with excluded namespace prefixes
+
+**Input XML:**
+```xml
+
+Q1 42
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+```
+
+**Output:**
+```xml
+
+Q1: 42
+```
+
+## Notes
+
+- Every XSLT document must have exactly one `xsl:stylesheet` (or `xsl:transform`) element as its document element.
+- Top-level elements must appear in a defined order when import precedence matters: `xsl:import` elements must come first, before any other children.
+- Extension element prefixes listed in `extension-element-prefixes` are not written to the output tree as namespace nodes; this keeps the output clean.
+- When a stylesheet is embedded inside an XML source document (using the `` processing instruction), the stylesheet element still requires the `version` and namespace attributes.
+
+## See also
+
+- [xsl:transform](../xsl-transform)
+- [xsl:template](../xsl-template)
+- [xsl:output](../xsl-output)
+- [xsl:import](../xsl-import)
+- [xsl:include](../xsl-include)
diff --git a/site/content/xslt/functions/xsl-template.md b/site/content/xslt/functions/xsl-template.md
new file mode 100644
index 00000000..c24220d1
--- /dev/null
+++ b/site/content/xslt/functions/xsl-template.md
@@ -0,0 +1,124 @@
+---
+title: "xsl:template"
+description: "Defines a template rule that fires when a node matches a pattern, or a named template that can be called explicitly."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:template` is the central building block of every XSLT stylesheet. It defines a reusable chunk of transformation logic that is either matched automatically by the XSLT processor when it encounters nodes of a certain type, or called explicitly by name from other templates.
+
+A template with a `match` attribute is a **template rule**. The processor evaluates the match pattern against nodes in the source tree and fires the template when a node matches. Patterns follow XPath abbreviated syntax with restrictions: only the child and attribute axes, predicates, and node tests are allowed — not full XPath expressions.
+
+A template with only a `name` attribute is a **named template**, similar to a function or subroutine. It is never fired automatically; it must be called with `xsl:call-template`. A template may have both `match` and `name`, making it both matchable and callable.
+
+The `mode` attribute allows the same source node to be processed by different templates in different contexts — for example, once to build a table of contents and again to build the body text. Templates with `mode` can only be activated by `xsl:apply-templates` with the same `mode` value.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `match` | Pattern | Conditional | XPath pattern that nodes must satisfy. Required unless `name` is present. |
+| `name` | QName | Conditional | Unique name for calling via `xsl:call-template`. Required unless `match` is present. |
+| `mode` | QName | No | Named processing mode; restricts when the template fires. |
+| `priority` | number | No | Explicit conflict-resolution priority. Higher number wins. |
+
+## Examples
+
+### Match-based template rule
+
+**Input XML:**
+```xml
+
+
+ Clean Code 2008
+ Refactoring 1999
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - Clean Code
+ - Refactoring
+
+```
+
+### Named template with parameters
+
+**Input XML:**
+```xml
+
+7
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *
+
+
+
+
+```
+
+**Output:**
+```
+*******
+```
+
+## Notes
+
+- When two template rules match the same node, the processor uses conflict resolution: higher `priority` wins. If priorities are equal, the template with the more specific pattern wins (attribute patterns beat element patterns beat wildcard patterns). If still ambiguous, the processor may signal an error or pick the last declared template.
+- Default built-in templates exist for every node type. For element and root nodes they recursively apply templates; for text and attribute nodes they copy the string value; for comments and processing instructions they produce nothing.
+- The `mode` attribute value `#all` (XSLT 2.0+) matches in any mode; in XSLT 1.0 mode names must be an ordinary QName.
+- Named templates do not have a `match` pattern, so they have no context node unless one is established by the caller.
+
+## See also
+
+- [xsl:apply-templates](../xsl-apply-templates)
+- [xsl:call-template](../xsl-call-template)
+- [xsl:with-param](../xsl-with-param)
+- [xsl:param](../xsl-param)
diff --git a/site/content/xslt/functions/xsl-text.md b/site/content/xslt/functions/xsl-text.md
new file mode 100644
index 00000000..48e9a5dc
--- /dev/null
+++ b/site/content/xslt/functions/xsl-text.md
@@ -0,0 +1,105 @@
+---
+title: "xsl:text"
+description: "Outputs literal text exactly as written, preserving all whitespace and optionally bypassing XML character escaping."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:text` inserts its text content into the result tree as a text node, preserving every whitespace character — spaces, tabs, newlines — exactly as they appear in the stylesheet. This is in contrast to bare text in a template body, where whitespace-only text nodes adjacent to XSLT instructions may be stripped by the processor.
+
+The primary purpose of `xsl:text` is to give precise control over whitespace in the output. It is also used to output special characters that would otherwise be awkward to write directly, such as newlines or tab characters, via XML character references (`
`, ` `).
+
+The optional `disable-output-escaping` attribute, when set to `yes`, tells the serializer not to escape characters like `<` and `&`. This can produce output that is not well-formed XML (for example, a literal ` ` in HTML output), so it should be used with care and only when the target format requires it.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `disable-output-escaping` | `yes` / `no` | No | If `yes`, characters are written literally without XML escaping. Default is `no`. |
+
+## Examples
+
+### Controlling separators in text output
+
+**Input XML:**
+```xml
+
+
+ Name Age City
+ Alice 30 Paris
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ ,
+
+
+
+
+
+
+```
+
+**Output:**
+```
+Name,Age,City
+Alice,30,Paris
+```
+
+### Preserving whitespace in XML output
+
+**Input XML:**
+```xml
+
+Hello World
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+Hello
+World
+
+```
+
+## Notes
+
+- `xsl:text` may only contain text — no child elements, not even XSLT instructions. Attribute value templates (`{...}`) are not available inside `xsl:text`; use `xsl:value-of` for dynamic values.
+- Whitespace-only text nodes elsewhere in a template body (between XSLT elements) are often stripped; wrapping them in `xsl:text` guarantees they are preserved.
+- `disable-output-escaping="yes"` is considered a low-level escape hatch and is not supported in all output modes or serializers. Avoid it unless absolutely necessary.
+- For producing newlines in text output, `
` (LF) is the most portable choice. Use `
` for CRLF when targeting Windows line endings.
+
+## See also
+
+- [xsl:value-of](../xsl-value-of)
+- [xsl:output](../xsl-output)
diff --git a/site/content/xslt/functions/xsl-transform.md b/site/content/xslt/functions/xsl-transform.md
new file mode 100644
index 00000000..72f744e2
--- /dev/null
+++ b/site/content/xslt/functions/xsl-transform.md
@@ -0,0 +1,92 @@
+---
+title: "xsl:transform"
+description: "Synonym for xsl:stylesheet — the root element of an XSLT stylesheet, interchangeable in every respect."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:transform` is a direct synonym for `xsl:stylesheet`. The XSLT 1.0 specification allows either name as the document element of a stylesheet, and conforming processors must accept both. All attributes, allowed child elements, and semantics are identical.
+
+In practice, `xsl:stylesheet` is used by the vast majority of published stylesheets because it was the name used in early drafts and became the de-facto convention. `xsl:transform` occasionally appears in generated or tool-produced stylesheets, and some authors prefer it because the word "transform" more directly describes what the document does.
+
+There is no technical reason to choose one over the other. If a project or team has adopted a consistent convention, follow it; otherwise, `xsl:stylesheet` is the safer choice for readability and tooling compatibility.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `version` | `"1.0"` / `"2.0"` / `"3.0"` | Yes | XSLT version governing this stylesheet. |
+| `id` | ID | No | Unique identifier for the element. |
+| `extension-element-prefixes` | whitespace-separated prefixes | No | Prefixes treated as extension element namespaces. |
+| `exclude-result-prefixes` | whitespace-separated prefixes | No | Prefixes excluded from the result tree. |
+
+## Examples
+
+### Using xsl:transform as root element
+
+**Input XML:**
+```xml
+
+
+ XSLT Patterns
+ Jane Doe
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+ by
+
+
+
+```
+
+**Output:**
+```
+XSLT Patterns by Jane Doe
+```
+
+### Equivalent xsl:stylesheet version
+
+**Stylesheet (identical result, different root name):**
+```xml
+
+
+
+
+
+
+ by
+
+
+
+```
+
+**Output:**
+```
+XSLT Patterns by Jane Doe
+```
+
+## Notes
+
+- The two names are specified as synonyms in the XSLT 1.0 Recommendation, section 2.2. No processor may accept one but reject the other.
+- Mixing them — e.g., opening with `` and closing with ` ` — is a well-formedness error in XML, not an XSLT issue.
+- Schema validators for XSLT documents (such as the official XSLT schema) list both names in the content model.
+
+## See also
+
+- [xsl:stylesheet](../xsl-stylesheet)
+- [xsl:template](../xsl-template)
+- [xsl:output](../xsl-output)
diff --git a/site/content/xslt/functions/xsl-try.md b/site/content/xslt/functions/xsl-try.md
new file mode 100644
index 00000000..040fe485
--- /dev/null
+++ b/site/content/xslt/functions/xsl-try.md
@@ -0,0 +1,111 @@
+---
+title: "xsl:try"
+description: "Evaluates an XPath expression or sequence constructor and catches any dynamic errors, enabling graceful error handling in XSLT 3.0."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:try` is the XSLT 3.0 mechanism for catching dynamic errors that occur during transformation. Before XSLT 3.0, any error in an XPath expression or instruction aborted the entire transformation. With `xsl:try` you can isolate a risky operation, catch the error with a paired `xsl:catch` block, and either recover gracefully or emit a meaningful error message.
+
+`xsl:try` works in two modes. In *expression mode*, you set the `select` attribute to an XPath expression whose value is returned if it succeeds. In *instruction mode*, you use a sequence constructor as the content of the element. Either way, if a dynamic error occurs within the try boundary, control transfers to the first matching `xsl:catch` sibling.
+
+Common use cases include: calling extension functions that may fail, parsing user-supplied data that might be malformed, accessing documents that might not exist (`doc()` on an unknown URI), and converting strings to typed values where the cast may raise an error.
+
+`xsl:try` does not catch static errors or type errors detected at compile time — only dynamic errors raised during evaluation.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `select` | expression | No | XPath expression to evaluate. Mutually exclusive with content. |
+
+## Examples
+
+### Safely parsing a date attribute
+
+**Input XML:**
+```xml
+
+
+ Conference
+ Workshop
+ Webinar
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ -
+
+
+ Invalid date
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - 15 March 2026
+ - Invalid date
+ - 1 April 2026
+
+```
+
+### Loading an optional document
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ light
+
+
+
+
+```
+
+## Notes
+
+- Every `xsl:try` must contain at least one `xsl:catch` as a direct child. Other content may appear alongside `xsl:catch`.
+- Variables declared inside `xsl:try` are not in scope in `xsl:catch`.
+- `xsl:try` is not streamable; it cannot be used inside a streaming template.
+- Inside `xsl:catch`, special variables `$err:code`, `$err:description`, `$err:value`, `$err:module`, `$err:line-number`, and `$err:column-number` are available.
+
+## See also
+
+- [xsl:catch](../xsl-catch)
diff --git a/site/content/xslt/functions/xsl-use-accumulators.md b/site/content/xslt/functions/xsl-use-accumulators.md
new file mode 100644
index 00000000..3e5ab304
--- /dev/null
+++ b/site/content/xslt/functions/xsl-use-accumulators.md
@@ -0,0 +1,142 @@
+---
+title: "xsl:use-accumulators"
+description: "Declares which accumulators are active for a streaming template or mode, enabling the processor to compute only necessary values."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:use-accumulators` is an attribute (expressed as a pseudo-element in older descriptions, but in current XSLT 3.0 it is an attribute on `xsl:template` or `xsl:mode`) that lists the accumulators that should be active while processing a streaming template. When streaming is in use, the XSLT processor cannot maintain all accumulators simultaneously because it processes nodes in document order without storing the full tree. Declaring which accumulators are needed allows the processor to activate only those, reducing memory and processing overhead.
+
+In practice, `xsl:use-accumulators` appears as the `use-accumulators` attribute on an `xsl:template` or `xsl:mode` element. The value is a whitespace-separated list of accumulator names (QNames). Only accumulators listed here are guaranteed to return meaningful values via `accumulator-before()` and `accumulator-after()` within the template's scope.
+
+If `use-accumulators` is absent on a streaming template, no accumulators are active by default. In non-streaming stylesheets, all accumulators defined in the stylesheet are available without declaring them.
+
+## Parameters
+
+| Attribute | Context | Type | Description |
+|-----------|---------|------|-------------|
+| `use-accumulators` | `xsl:template` or `xsl:mode` | `xs:QName*` whitespace-separated | Names of accumulators to activate for this template or mode. |
+
+## Return value
+
+`xsl:use-accumulators` is a declaration attribute; it produces no XDM value.
+
+## Examples
+
+### Streaming a large document and reading a running total accumulator
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Input XML (`sales.xml`):**
+```xml
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+
+
+
+ 425.75
+
+```
+
+### Using multiple accumulators in a streaming mode
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ 3
+ 435.75
+
+```
+
+## Notes
+
+- `use-accumulators` is only required (and only meaningful) in streaming contexts. In non-streaming stylesheets, all accumulators defined in the stylesheet are implicitly available.
+- Referencing `accumulator-before()` or `accumulator-after()` for an accumulator not listed in `use-accumulators` is a static error when streaming is enabled.
+- The attribute value is a whitespace-separated list of QNames, not an XPath expression. If an accumulator is in a namespace, the QName must use a prefix bound in the stylesheet.
+- Activating unused accumulators in a streaming template wastes memory; list only those actually queried in the template.
+
+## See also
+
+- [xsl:accumulator](../xsl-accumulator)
+- [xsl:accumulator-rule](../xsl-accumulator-rule)
+- [accumulator-before()](../xpath-accumulator-before)
+- [accumulator-after()](../xpath-accumulator-after)
diff --git a/site/content/xslt/functions/xsl-use-package.md b/site/content/xslt/functions/xsl-use-package.md
new file mode 100644
index 00000000..9a45c720
--- /dev/null
+++ b/site/content/xslt/functions/xsl-use-package.md
@@ -0,0 +1,117 @@
+---
+title: "xsl:use-package"
+description: "Declares that the current stylesheet or package uses components from a named external XSLT 3.0 package."
+date: 2026-04-19T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: ""
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:use-package` appears as a top-level child of `xsl:stylesheet` or `xsl:package` and declares a dependency on an external XSLT 3.0 package. Once declared, the public and final components of the used package—templates, functions, variables, attribute sets, modes, and types—become available in the current stylesheet as if they were declared locally.
+
+Unlike `xsl:import`, which merges stylesheets textually and uses import precedence to resolve conflicts, `xsl:use-package` is a formal dependency declaration with strict encapsulation. Only components explicitly marked `public` or `final` in the used package's `xsl:expose` declarations are accessible; private components remain hidden.
+
+Two child elements extend the behaviour of `xsl:use-package`: `xsl:accept` narrows or hides specific public components in the current context, and `xsl:override` provides local replacements for components that the package declared as overridable (i.e., not `final`).
+
+## Parameters
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | `xs:anyURI` | Yes | The URI name of the package to use (must match the `name` attribute of the target `xsl:package`). |
+| `package-version` | `xs:string` | Yes | A version pattern selecting which package versions are acceptable. Use `*` for any version. |
+
+## Return value
+
+`xsl:use-package` is a declaration; it does not produce an XDM value.
+
+## Examples
+
+### Basic usage of a utility package
+
+**Stylesheet consuming a formatting package:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output (given ` `):**
+```xml
+
+ $1,250.50
+
+```
+
+### Accepting a subset of components and overriding a template
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```html
+
+
+
+
+```
+
+## Notes
+
+- A stylesheet may have multiple `xsl:use-package` declarations, one per dependency.
+- The `package-version` pattern supports wildcards. `"1.*"` matches any version starting with `1.`; `"*"` matches all versions.
+- When multiple versions of the same package are available, the processor selects the best match according to the W3C version matching rules.
+- Circular dependencies between packages are not allowed.
+- In Saxon, packages must be pre-compiled to SEF format or provided as source files in the classpath configuration before `xsl:use-package` can resolve them.
+
+## See also
+
+- [xsl:package](../xsl-package)
+- [xsl:accept](../xsl-accept)
+- [xsl:override](../xsl-override)
diff --git a/site/content/xslt/functions/xsl-variable.md b/site/content/xslt/functions/xsl-variable.md
new file mode 100644
index 00000000..887d103f
--- /dev/null
+++ b/site/content/xslt/functions/xsl-variable.md
@@ -0,0 +1,116 @@
+---
+title: "xsl:variable"
+description: "Binds a name to a value or node-set for the duration of the enclosing scope; XSLT variables are immutable once set."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:variable` binds a name to a computed value. Once the binding is established it cannot be changed — XSLT variables are constants in the sense that reassignment is not possible. This immutability is a fundamental design decision that enables the functional, side-effect-free processing model of XSLT.
+
+A variable can be declared at two levels:
+
+- **Top-level** (direct child of `xsl:stylesheet`): the variable is global and visible in all templates throughout the stylesheet and any included or importing stylesheets.
+- **Inside a template**: the variable is local and visible only in the subsequent siblings and their descendants within the same template scope.
+
+The value of a variable is determined either by the `select` attribute (an XPath expression) or by the element's content. If neither is present, the variable has an empty string value. If both are present, it is an error.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | The variable name, referenced in XPath as `$name`. |
+| `select` | XPath expression | No | Expression whose value becomes the variable's value. Mutually exclusive with element content. |
+| `as` | SequenceType | No | (2.0+) Declares the expected type; triggers a type error if the value does not match. |
+
+## Examples
+
+### Local variable for intermediate computation
+
+**Input XML:**
+```xml
+
+
+ - Widget
+ - Bolt
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Widget 37.50
+ Bolt 50.00
+
+```
+
+### Global variable and content-based variable
+
+**Input XML:**
+```xml
+
+Annual Report 2025
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+ Acme Corp
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Annual Report — Acme Corp 2025
+
+```
+
+## Notes
+
+- A local `xsl:variable` does not shadow or override a global variable of the same name within the current scope; it creates a new binding that takes precedence locally.
+- Because variables are immutable, the common pattern for conditional assignment is `xsl:choose` inside a content-based variable declaration.
+- Circular variable references (a global variable referencing itself) are an error.
+- In XSLT 1.0, a content-based variable that produces a result tree fragment (RTF) can only be used with `string()`, `boolean()`, `number()`, or passed to `xsl:copy-of`. To use it as a node-set, you need the `node-set()` extension function (e.g., `exsl:node-set()`).
+
+## See also
+
+- [xsl:param](../xsl-param)
+- [xsl:with-param](../xsl-with-param)
diff --git a/site/content/xslt/functions/xsl-when.md b/site/content/xslt/functions/xsl-when.md
new file mode 100644
index 00000000..eb142f0d
--- /dev/null
+++ b/site/content/xslt/functions/xsl-when.md
@@ -0,0 +1,133 @@
+---
+title: "xsl:when"
+description: "Condition branch inside xsl:choose; its content is output when test evaluates to true and no earlier sibling matched."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ''
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:when` is a child element of `xsl:choose` that represents one conditional branch. Its `test` attribute holds a boolean XPath expression. The parent `xsl:choose` evaluates the tests of its `xsl:when` children in document order and instantiates the content of the first one whose test is true. All subsequent `xsl:when` elements (and `xsl:otherwise`, if present) are skipped.
+
+`xsl:when` cannot appear outside of `xsl:choose`, and every `xsl:choose` must contain at least one `xsl:when`.
+
+The `test` expression follows the same rules as the `xsl:if` test: the result is coerced to boolean if it is not already one. An empty node-set, zero, `NaN`, or an empty string are all false; everything else is true.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `test` | Boolean XPath expression | Yes | Condition that must be true for this branch to be selected. |
+
+## Examples
+
+### Status label with multiple branches
+
+**Input XML:**
+```xml
+
+
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Awaiting processing
+ In transit
+ Completed
+ Unknown status
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Awaiting processing
+ In transit
+ Completed
+ Unknown status
+
+```
+
+### Positional branch
+
+**Input XML:**
+```xml
+
+
+ - Alpha
+ - Beta
+ - Gamma
+ - Delta
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+ -
+
+ first
+ last
+ middle
+
+ :
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ - first: Alpha
+ - middle: Beta
+ - middle: Gamma
+ - last: Delta
+
+```
+
+## Notes
+
+- Conditions are tested strictly in order; once a match is found, no further `xsl:when` conditions are evaluated. Arrange branches from most specific to most general to avoid ambiguity.
+- The content of an unmatched `xsl:when` is never instantiated, so side effects (like `xsl:message`) inside it will not occur.
+- In XSLT 2.0+ the `test` attribute can contain any XPath 2.0 expression; the coercion rules are more strict than in 1.0 (only `xs:boolean` and node-sets are accepted without explicit conversion).
+
+## See also
+
+- [xsl:choose](../xsl-choose)
+- [xsl:otherwise](../xsl-otherwise)
+- [xsl:if](../xsl-if)
diff --git a/site/content/xslt/functions/xsl-where-populated.md b/site/content/xslt/functions/xsl-where-populated.md
new file mode 100644
index 00000000..47a93879
--- /dev/null
+++ b/site/content/xslt/functions/xsl-where-populated.md
@@ -0,0 +1,113 @@
+---
+title: "xsl:where-populated"
+description: "Suppresses the entire wrapper element, including its start and end tags, when its content sequence constructor produces no nodes."
+date: 2026-04-18T00:00:00Z
+version: "3.0"
+versionLabel: "XSLT 3.0"
+category: "element"
+syntax: "... "
+tags: ["xslt", "reference", "xslt3"]
+---
+
+## Description
+
+`xsl:where-populated` wraps an element constructor and suppresses the *entire* wrapper — open tag, close tag, and everything between — if the content would be empty. This differs from `xsl:on-empty`, which generates fallback content, and from `xsl:on-non-empty`, which conditionally prepends content. `xsl:where-populated` is about wholesale suppression of a wrapping element.
+
+The most frequent problem it solves is the "empty wrapper" antipattern: you want to emit `... ` only when there are errors, but you cannot know in advance whether any errors exist. The naive approach tests with a variable or `count()`. With `xsl:where-populated` you write the element constructor normally and let the processor decide at runtime whether to emit it.
+
+`xsl:where-populated` must contain exactly one element constructor (a literal result element or `xsl:element`) as its direct child. The processor evaluates the children of that element; if the result is empty, neither the inner element nor `xsl:where-populated` emits anything. If the result is non-empty, the inner element is written to the output as usual.
+
+This element is particularly powerful in streaming stylesheets, where you cannot look ahead.
+
+## Attributes
+
+`xsl:where-populated` has no element-specific attributes. It must contain a single element-constructing child.
+
+## Examples
+
+### Suppress an empty errors wrapper
+
+**Input XML:**
+```xml
+
+
+
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+ jobs processed.
+
+
+
+
+
+
+
+
+```
+
+**Output (no errors element because no failed jobs):**
+```xml
+
+ 2 jobs processed.
+
+```
+
+### Combining with xsl:apply-templates in a streaming context
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Notes
+
+- The direct child of `xsl:where-populated` must be a single element constructor. Wrapping multiple elements requires an outer `xsl:element` or restructuring.
+- Text nodes, comments, and processing instructions produced by the inner content are all considered "populated".
+- `xsl:where-populated` is streamable.
+- It cannot be used to suppress non-element output (e.g. a text node or attribute) — use `xsl:on-empty` for that pattern instead.
+
+## See also
+
+- [xsl:on-empty](../xsl-on-empty)
+- [xsl:on-non-empty](../xsl-on-non-empty)
diff --git a/site/content/xslt/functions/xsl-with-param.md b/site/content/xslt/functions/xsl-with-param.md
new file mode 100644
index 00000000..55b75ff9
--- /dev/null
+++ b/site/content/xslt/functions/xsl-with-param.md
@@ -0,0 +1,127 @@
+---
+title: "xsl:with-param"
+description: "Supplies a parameter value to a called or applied template, overriding that template's declared default."
+date: 2026-04-18T00:00:00Z
+version: "1.0"
+versionLabel: "XSLT 1.0"
+category: "element"
+syntax: ' '
+tags: ["xslt", "reference", "xslt1"]
+---
+
+## Description
+
+`xsl:with-param` is used inside `xsl:call-template` or `xsl:apply-templates` to pass a value to a parameter declared with `xsl:param` in the target template. It is the mechanism that allows XSLT's otherwise static templates to behave like parameterised subroutines.
+
+The `name` attribute must match the `name` of an `xsl:param` in the called or matched template. The value is specified either via the `select` attribute (an XPath expression evaluated in the current context) or via element content (a result tree fragment). If the target template does not declare a parameter with that name, the value is silently ignored in XSLT 1.0.
+
+`xsl:with-param` must appear as a child of `xsl:call-template` or `xsl:apply-templates` before any other content. When used with `xsl:apply-templates`, all selected nodes receive the same parameter value.
+
+## Attributes
+
+| Attribute | Type | Required | Description |
+|-----------|------|----------|-------------|
+| `name` | QName | Yes | Name of the target parameter, matching an `xsl:param` declaration. |
+| `select` | XPath expression | No | Expression evaluated in the calling context; its result is the parameter value. |
+| `as` | SequenceType | No | (2.0+) Expected type of the value being passed. |
+| `tunnel` | `yes` / `no` | No | (2.0+) If `yes`, the parameter is forwarded through intermediate templates automatically. |
+
+## Examples
+
+### Passing a counter through recursive calls
+
+**Input XML:**
+```xml
+
+5
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```
+5
+4
+3
+2
+1
+```
+
+### Passing a label to applied templates
+
+**Input XML:**
+```xml
+
+
+```
+
+**Stylesheet:**
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Output:**
+```xml
+
+ Alpha
+ Beta
+
+```
+
+## Notes
+
+- In XSLT 1.0, passing a parameter to a template that does not declare it causes no error — the value is silently discarded. This can hide mistakes; double-check parameter names carefully.
+- `xsl:with-param` is evaluated in the context of the calling template, not the called template. XPath expressions see the calling template's variables and context node.
+- When used inside `xsl:apply-templates`, all matching templates receive the same parameter values. There is no per-node variation unless you compute different values per node inside the templates themselves.
+- Content-based `xsl:with-param` (no `select`, with element children) produces a result tree fragment in XSLT 1.0, subject to the same RTF restrictions as `xsl:variable`.
+
+## See also
+
+- [xsl:param](../xsl-param)
+- [xsl:call-template](../xsl-call-template)
+- [xsl:apply-templates](../xsl-apply-templates)
+- [xsl:variable](../xsl-variable)