mirror of
https://github.com/alexandrev/xslt-lab.git
synced 2026-09-16 18:23:16 +00:00
feat(blog): XSLT/XPath function reference section (Phase 2)
- 19 reference pages under /xslt/functions/ covering: xsl:value-of, xsl:for-each, xsl:for-each-group, xsl:function, xsl:iterate, last(), position(), count(), concat(), contains(), substring(), sum(), key(), current(), string-join(), tokenize(), matches(), replace(), format-date() - Each page: description, parameters table, return value, 2 runnable examples (input XML + stylesheet + output), notes, cross-links - New Hugo section with reference-specific layout (version badges, syntax block, "Try in Playground" CTA, parameters table styles) - Menu entry "Reference" → /xslt/functions/ - CSS: .ref-badge, .ref-syntax, .ref-index-list, .ref-try + table styles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
---
|
||||
title: "XSLT Reference"
|
||||
description: "Reference documentation for XSLT elements and XPath functions."
|
||||
---
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
title: "XSLT & XPath Function Reference"
|
||||
description: "Complete reference for XSLT elements and XPath functions with syntax, parameters, and runnable examples. Covers XSLT 1.0, 2.0, and 3.0."
|
||||
---
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: "concat()"
|
||||
description: "Concatenates two or more strings into a single string, accepting any number of arguments."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "string function"
|
||||
syntax: "concat(str1, str2, ...)"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`concat()` joins two or more string arguments into a single string, in the order they are provided. Each argument is converted to a string using the XPath string-value rules before concatenation.
|
||||
|
||||
It requires **at least two arguments** but accepts any number. Arguments that are not strings (numbers, booleans, nodes) are automatically cast to their string representation.
|
||||
|
||||
`concat()` is the standard way to build dynamic attribute values, filenames, URIs, or any computed string in XSLT 1.0. In XSLT 2.0+, `string-join()` is often more readable when the separator is uniform.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `str1` | xs:anyAtomicType | Yes | First string (or value convertible to string). |
|
||||
| `str2` | xs:anyAtomicType | Yes | Second string. |
|
||||
| `...` | xs:anyAtomicType | No | Additional strings; at least two arguments are required. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — all arguments concatenated in order, with no separator.
|
||||
|
||||
## Examples
|
||||
|
||||
### Build a full name
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<person>
|
||||
<first>Jane</first>
|
||||
<last>Smith</last>
|
||||
</person>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/person">
|
||||
<xsl:value-of select="concat(first, ' ', last)"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Jane Smith
|
||||
```
|
||||
|
||||
### Dynamic attribute value
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/person">
|
||||
<a href="{concat('/profile/', first, '-', last)}">
|
||||
<xsl:value-of select="concat(first, ' ', last)"/>
|
||||
</a>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<a href="/profile/Jane-Smith">Jane Smith</a>
|
||||
```
|
||||
|
||||
### Concatenate node values and literals
|
||||
|
||||
```xml
|
||||
<!-- Compose a greeting -->
|
||||
<xsl:value-of select="concat('Hello, ', /person/first, '! You have ', count(//message), ' messages.')"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `concat()` does not add any separator between arguments. To join with a separator, either include the separator as a literal argument or use `string-join()` (XSLT 2.0+).
|
||||
- Unlike `string-join()`, `concat()` does not accept a sequence; each argument must be a single value.
|
||||
- Attribute value templates `{expression}` are a shorthand alternative for simple cases and can call `concat()` inside them.
|
||||
- Numbers are converted to their canonical string form: `concat(1.0, 'x')` produces `"1x"` not `"1.0x"` (the exact output depends on the XPath string conversion rules).
|
||||
|
||||
## See also
|
||||
|
||||
- [string-join()](../xpath-string-join)
|
||||
- [contains()](../xpath-contains)
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: "contains()"
|
||||
description: "Returns true if the first string contains the second string as a substring, otherwise returns false."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "string function"
|
||||
syntax: "contains(string, substring)"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`contains()` tests whether a string includes a given substring and returns a boolean result. Both arguments are converted to strings before the comparison.
|
||||
|
||||
The comparison is **case-sensitive** and uses code-point ordering. If you need case-insensitive matching, use `matches()` with the `i` flag (XSLT 2.0+) or normalize both strings with `lower-case()` before comparing.
|
||||
|
||||
If the second argument is an empty string, `contains()` always returns `true` because every string contains the empty string.
|
||||
|
||||
`contains()` is frequently used inside `xsl:if` and `xsl:when` predicates to filter elements based on string content, or in predicates within XPath expressions.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string | Yes | The string to search within. |
|
||||
| `substring` | xs:string | Yes | The substring to look for. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if `string` contains `substring`, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Filter elements by content
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<articles>
|
||||
<article><title>XSLT Tutorial for Beginners</title></article>
|
||||
<article><title>Advanced XML Schema</title></article>
|
||||
<article><title>XSLT 2.0 Features</title></article>
|
||||
</articles>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/articles">
|
||||
<xslt-articles>
|
||||
<xsl:for-each select="article[contains(title, 'XSLT')]">
|
||||
<item><xsl:value-of select="title"/></item>
|
||||
</xsl:for-each>
|
||||
</xslt-articles>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<xslt-articles>
|
||||
<item>XSLT Tutorial for Beginners</item>
|
||||
<item>XSLT 2.0 Features</item>
|
||||
</xslt-articles>
|
||||
```
|
||||
|
||||
### Conditional processing
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/articles">
|
||||
<results>
|
||||
<xsl:for-each select="article">
|
||||
<xsl:if test="contains(title, 'XSLT')">
|
||||
<match><xsl:value-of select="title"/></match>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<match>XSLT Tutorial for Beginners</match>
|
||||
<match>XSLT 2.0 Features</match>
|
||||
</results>
|
||||
```
|
||||
|
||||
### Combined with other string functions
|
||||
|
||||
```xml
|
||||
<!-- Check if a URL contains 'https' -->
|
||||
<xsl:if test="contains(@href, 'https')">
|
||||
<xsl:attribute name="secure">true</xsl:attribute>
|
||||
</xsl:if>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `contains()` is case-sensitive. For case-insensitive checks in XSLT 2.0+, use `matches(., 'pattern', 'i')` or `contains(lower-case(title), 'xslt')`.
|
||||
- To check if a string **starts with** a value, use `starts-with()`. To check a suffix, use `ends-with()` (XSLT 2.0+) or `substring()`.
|
||||
- `contains()` returns `true` when the substring argument is empty, which can cause unexpected results in dynamic expressions.
|
||||
- For complex pattern matching (wildcards, character classes), use `matches()` instead.
|
||||
|
||||
## See also
|
||||
|
||||
- [matches()](../xpath-matches)
|
||||
- [substring()](../xpath-substring)
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: "count()"
|
||||
description: "Returns the number of nodes in a node-set or items in a sequence as an integer."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "count(node-set)"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`count()` evaluates an XPath expression, collects the resulting node-set (or sequence in XPath 2.0+), and returns the number of items as an integer. It is the standard way to determine how many elements match a given path without iterating over them.
|
||||
|
||||
Common use cases include:
|
||||
|
||||
- Conditionally processing content only if at least one element exists.
|
||||
- Displaying totals ("5 items found").
|
||||
- Checking whether a repeated element has a specific number of occurrences.
|
||||
- Using the count as a denominator or comparator in arithmetic expressions.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node-set` | node-set / sequence | Yes | The node-set or sequence whose size is returned. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer` — the number of nodes or items in the argument.
|
||||
|
||||
## Examples
|
||||
|
||||
### Display item count
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<library>
|
||||
<book><title>XSLT Cookbook</title></book>
|
||||
<book><title>XML in a Nutshell</title></book>
|
||||
<book><title>Learning XML</title></book>
|
||||
</library>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/library">
|
||||
<xsl:value-of select="count(book)"/>
|
||||
<xsl:text> books in the library.</xsl:text>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
3 books in the library.
|
||||
```
|
||||
|
||||
### Conditional output based on count
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/library">
|
||||
<result>
|
||||
<xsl:choose>
|
||||
<xsl:when test="count(book) = 0">
|
||||
<message>No books found.</message>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<message><xsl:value-of select="count(book)"/> book(s) found.</message>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<message>3 book(s) found.</message>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Count elements matching a condition
|
||||
|
||||
```xml
|
||||
<!-- Count books with more than 300 pages -->
|
||||
<xsl:value-of select="count(book[@pages > 300])"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `count()` counts nodes in the argument expression, not the context node's children by default. Always specify the path explicitly.
|
||||
- To count all descendants of a type, use `count(.//element-name)`.
|
||||
- `count()` always returns a non-negative integer; it returns `0` for an empty node-set, never an error.
|
||||
- In XSLT 2.0+, you can use `count()` on any sequence, including sequences of atomic values.
|
||||
- `last()` inside `xsl:for-each` gives the same number as `count(select-expression)` but only within the loop; `count()` can be used anywhere.
|
||||
|
||||
## See also
|
||||
|
||||
- [sum()](../xpath-sum)
|
||||
- [last()](../xpath-last)
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: "current()"
|
||||
description: "Returns the context node of the innermost xsl:template or xsl:for-each, unaffected by nested predicates."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "current()"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current()` returns the **current node** — the node being processed by the nearest enclosing `xsl:template` or `xsl:for-each` instruction. This is different from the **context node** (`.`), which shifts to each node evaluated inside predicates and path steps.
|
||||
|
||||
The key distinction is:
|
||||
|
||||
- `.` (dot) refers to the node currently in focus in an XPath sub-expression, which can change as XPath navigates through predicates.
|
||||
- `current()` always refers to the XSLT processing context (the node the instruction is currently transforming), regardless of how deeply nested the XPath expression is.
|
||||
|
||||
`current()` is most useful inside predicates when you need to refer back to the outer node being processed, for example to perform a cross-reference lookup based on a value from the current node.
|
||||
|
||||
`current()` is an XSLT function, not a pure XPath function — it is only valid inside XSLT stylesheets, not standalone XPath expressions.
|
||||
|
||||
## Return value
|
||||
|
||||
A node-set containing exactly one node: the current XSLT processing context node.
|
||||
|
||||
## Examples
|
||||
|
||||
### Cross-reference using current() in a predicate
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<categories>
|
||||
<category id="A">Electronics</category>
|
||||
<category id="B">Books</category>
|
||||
</categories>
|
||||
<products>
|
||||
<product cat="A"><name>Laptop</name></product>
|
||||
<product cat="B"><name>XSLT Guide</name></product>
|
||||
</products>
|
||||
</root>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/root">
|
||||
<result>
|
||||
<xsl:for-each select="products/product">
|
||||
<item>
|
||||
<xsl:value-of select="name"/>
|
||||
<xsl:text> — </xsl:text>
|
||||
<!-- current() is the product; . inside the predicate would be the category -->
|
||||
<xsl:value-of select="/root/categories/category[@id = current()/@cat]"/>
|
||||
</item>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<item>Laptop — Electronics</item>
|
||||
<item>XSLT Guide — Books</item>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Why current() differs from dot
|
||||
|
||||
```xml
|
||||
<!-- Inside the predicate, "." refers to the category node, not the product.
|
||||
Without current(), @cat would look for an attribute on the category element. -->
|
||||
|
||||
<!-- Correct: -->
|
||||
<xsl:value-of select="/root/categories/category[@id = current()/@cat]"/>
|
||||
|
||||
<!-- Wrong (would compare @id to category's own @cat, not the product's @cat): -->
|
||||
<xsl:value-of select="/root/categories/category[@id = @cat]"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `current()` is only meaningful inside an `xsl:template` or `xsl:for-each`. Calling it at the top level of a match pattern is an error.
|
||||
- It cannot be used inside `xsl:key`'s `use` attribute — that is evaluated outside of any XSLT instruction context.
|
||||
- In XSLT 2.0+, the need for `current()` is often reduced by using variables (`xsl:variable`) to capture the node before entering a predicate.
|
||||
- `current()` and `.` are identical outside any predicate or path step.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:for-each](../xsl-for-each)
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
title: "format-date()"
|
||||
description: "Formats an xs:date 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-date(date, picture, language?, calendar?, place?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`format-date()` converts an `xs:date` value into a formatted string according to a **picture pattern**. It is the standard way in XSLT 2.0+ to produce locale-aware, human-readable date output from typed date values.
|
||||
|
||||
The picture string uses component specifiers enclosed in square brackets:
|
||||
|
||||
| Specifier | Meaning |
|
||||
|-----------|---------|
|
||||
| `[Y]` | Year (4 digits by default) |
|
||||
| `[M]` | Month as a number |
|
||||
| `[MNn]` | Month name (e.g., "April") |
|
||||
| `[D]` | Day of the month |
|
||||
| `[d]` | Day of the year |
|
||||
| `[F]` | Day of the week name (e.g., "Monday") |
|
||||
| `[FNn]` | Day of week, title case |
|
||||
| `[W]` | Week of the year |
|
||||
|
||||
Width modifiers control zero-padding: `[D01]` formats day as two digits (`01`, `15`). The `[MNn]` modifier requests the name in title case; `[MN]` gives uppercase.
|
||||
|
||||
Related functions cover time and combined date-time values:
|
||||
- `format-time(time, picture, ...)` for `xs:time` values.
|
||||
- `format-dateTime(dateTime, picture, ...)` for `xs:dateTime` values.
|
||||
|
||||
To get today's date for formatting, use `current-date()`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `date` | xs:date? | Yes | The date value to format. If an empty sequence, an empty string is returned. |
|
||||
| `picture` | xs:string | Yes | The picture pattern controlling the output format. |
|
||||
| `language` | xs:string? | No | BCP 47 language tag controlling names (e.g., `"en"`, `"fr"`, `"de"`). |
|
||||
| `calendar` | xs:string? | No | Calendar system identifier (e.g., `"AD"`, `"ISO"`). Implementation-defined. |
|
||||
| `place` | xs:string? | No | Place or timezone identifier. Implementation-defined. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the formatted date string, or an empty string if `date` is an empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Format a date attribute
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<events>
|
||||
<event date="2026-04-18">XSLT Conference</event>
|
||||
<event date="2026-12-25">Holiday</event>
|
||||
</events>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/events">
|
||||
<events>
|
||||
<xsl:for-each select="event">
|
||||
<event>
|
||||
<date><xsl:value-of select="format-date(xs:date(@date), '[FNn], [D] [MNn] [Y]')"/></date>
|
||||
<name><xsl:value-of select="."/></name>
|
||||
</event>
|
||||
</xsl:for-each>
|
||||
</events>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<events>
|
||||
<event>
|
||||
<date>Saturday, 18 April 2026</date>
|
||||
<name>XSLT Conference</name>
|
||||
</event>
|
||||
<event>
|
||||
<date>Friday, 25 December 2026</date>
|
||||
<name>Holiday</name>
|
||||
</event>
|
||||
</events>
|
||||
```
|
||||
|
||||
### Today's date formatted
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:value-of select="format-date(current-date(), '[D01]/[M01]/[Y]')"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```
|
||||
18/04/2026
|
||||
```
|
||||
|
||||
### French locale month name
|
||||
|
||||
```xml
|
||||
<xsl:value-of select="format-date(xs:date(@date), '[D] [MNn] [Y]', 'fr', (), ())"/>
|
||||
<!-- Output example: 18 avril 2026 -->
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The input must be an `xs:date` (not a string). Cast string date values with `xs:date(@date)` before calling `format-date()`.
|
||||
- Picture patterns are **not** the same as Java `SimpleDateFormat` or `strftime`. Refer to the XPath/XSLT 2.0 specification for the full picture syntax.
|
||||
- Language support depends on the XSLT processor. Saxon supports common European languages; less common locales may fall back to English.
|
||||
- For `xs:dateTime` values, use `format-dateTime()` which additionally supports time component specifiers like `[H]` (hour), `[m]` (minute), `[s]` (second).
|
||||
- `current-date()` returns the processor's current date as `xs:date`; pair it with `format-date()` to embed a build timestamp in the output.
|
||||
|
||||
## See also
|
||||
|
||||
- [current()](../xpath-current)
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "key()"
|
||||
description: "Looks up nodes using a named xsl:key index, returning all nodes whose key value matches the given value."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "key(name, value)"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`key()` retrieves nodes from the source document that have been indexed by an `xsl:key` declaration. It is essentially a pre-built hash-map lookup: you declare the index once with `xsl:key`, and then query it efficiently with `key()`.
|
||||
|
||||
The function is used for two main purposes:
|
||||
|
||||
1. **Cross-reference lookups** — retrieving a node by an ID-like value without iterating the entire document (much faster than `//element[@id='x']` in large documents).
|
||||
2. **Muenchian grouping** (XSLT 1.0) — identifying the first node of each group by combining `key()` with `generate-id()`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | string literal | Yes | The name of the `xsl:key` index to query (must match the `name` attribute of an `xsl:key` declaration). |
|
||||
| `value` | string / node-set | Yes | The key value to look up. If a node-set, the result is the union of nodes matching each node's string value. |
|
||||
|
||||
### Prerequisite: `xsl:key` declaration
|
||||
|
||||
```xml
|
||||
<xsl:key name="key-name" match="node-pattern" use="key-expression"/>
|
||||
```
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `match` | Pattern identifying which nodes to index. |
|
||||
| `use` | Expression that provides the key value for each matched node. |
|
||||
|
||||
## Return value
|
||||
|
||||
A node-set containing all nodes matched by `match` in `xsl:key` whose `use` expression equals `value`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Cross-reference lookup
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<departments>
|
||||
<dept id="D1">Engineering</dept>
|
||||
<dept id="D2">Marketing</dept>
|
||||
</departments>
|
||||
<employees>
|
||||
<employee dept="D1"><name>Alice</name></employee>
|
||||
<employee dept="D2"><name>Bob</name></employee>
|
||||
<employee dept="D1"><name>Carol</name></employee>
|
||||
</employees>
|
||||
</root>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:key name="dept-by-id" match="dept" use="@id"/>
|
||||
|
||||
<xsl:template match="/root">
|
||||
<report>
|
||||
<xsl:for-each select="employees/employee">
|
||||
<item>
|
||||
<xsl:value-of select="name"/>
|
||||
<xsl:text> — </xsl:text>
|
||||
<xsl:value-of select="key('dept-by-id', @dept)"/>
|
||||
</item>
|
||||
</xsl:for-each>
|
||||
</report>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<report>
|
||||
<item>Alice — Engineering</item>
|
||||
<item>Bob — Marketing</item>
|
||||
<item>Carol — Engineering</item>
|
||||
</report>
|
||||
```
|
||||
|
||||
### Muenchian grouping (XSLT 1.0)
|
||||
|
||||
```xml
|
||||
<xsl:key name="by-category" match="product" use="category"/>
|
||||
|
||||
<!-- Select the first product of each distinct category -->
|
||||
<xsl:for-each select="product[generate-id() = generate-id(key('by-category', category)[1])]">
|
||||
<group category="{category}">
|
||||
<xsl:value-of select="count(key('by-category', category))"/> items
|
||||
</group>
|
||||
</xsl:for-each>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `key()` only works within the **current document** by default. Use `key()` combined with `document()` to look up across external documents.
|
||||
- The XSLT processor builds the key index once per document, making `key()` significantly faster than predicate-based searches for repeated lookups.
|
||||
- In XSLT 2.0+, `xsl:for-each-group` replaces Muenchian grouping with a cleaner syntax.
|
||||
- If `name` does not match any `xsl:key` declaration, the result is an error.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:for-each-group](../xsl-for-each-group)
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: "last()"
|
||||
description: "Returns the size of the context node-set, i.e. the index of the last item in the current iteration context."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "last()"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`last()` returns an integer equal to the **context size** — the total number of nodes in the node-set (or items in the sequence) currently being processed. It takes no arguments.
|
||||
|
||||
The most common use cases are:
|
||||
|
||||
- Detecting the last item in a loop to apply different formatting (e.g., omitting a trailing separator).
|
||||
- Building predicates like `item[last()]` to select only the final element in a set.
|
||||
- Combining with `position()` to produce row counts or progress labels.
|
||||
|
||||
The value of `last()` changes with the context. Inside `xsl:for-each`, it reflects the number of items selected by the `select` attribute. Inside a template triggered by `xsl:apply-templates`, it reflects the number of nodes sent to that template call.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer` — the total number of items in the current context sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Omit trailing comma
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<colors>
|
||||
<color>Red</color>
|
||||
<color>Green</color>
|
||||
<color>Blue</color>
|
||||
</colors>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/colors">
|
||||
<xsl:for-each select="color">
|
||||
<xsl:value-of select="."/>
|
||||
<xsl:if test="position() != last()">, </xsl:if>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Red, Green, Blue
|
||||
```
|
||||
|
||||
### Select only the last element
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/colors">
|
||||
<xsl:value-of select="color[last()]"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Blue
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `last()` and `position()` are context-dependent. Their values inside a predicate differ from their values in the body of `xsl:for-each` — predicates establish their own context.
|
||||
- In XSLT 2.0+ with typed sequences, `last()` still works the same way but the context is an `xs:integer`-typed sequence size.
|
||||
- A common mistake is calling `last()` outside any iterating context; at the top level of a template, it returns 1 (the single context node).
|
||||
|
||||
## See also
|
||||
|
||||
- [position()](../xpath-position)
|
||||
- [count()](../xpath-count)
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
title: "matches()"
|
||||
description: "Tests whether a string matches a regular expression, returning true or false."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "matches(string, pattern, flags?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`matches()` tests whether the input `string` matches the regular expression `pattern` and returns `true` or `false`. By default the entire string does not need to match — the pattern is matched anywhere within the string (like a "contains" regex test). To anchor the match to the full string, use `^` and `$` anchors in the pattern.
|
||||
|
||||
The optional `flags` argument controls matching behaviour:
|
||||
|
||||
| Flag | Meaning |
|
||||
|------|---------|
|
||||
| `i` | Case-insensitive matching. |
|
||||
| `m` | Multiline mode: `^` and `$` match at line boundaries. |
|
||||
| `s` | Dot-all mode: `.` matches any character including newline. |
|
||||
| `x` | Extended mode: whitespace and `#` comments are ignored in the pattern. |
|
||||
|
||||
`matches()` uses XML Schema / XPath regex syntax, which is similar to but not identical to Perl/PCRE regex. Notably, lookaheads and backreferences are not supported.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string | Yes | The string to test. |
|
||||
| `pattern` | xs:string | Yes | The regular expression pattern. |
|
||||
| `flags` | xs:string | No | One or more flag characters controlling match behaviour. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the pattern matches anywhere in the string (unless anchored), `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Validate a format
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<entries>
|
||||
<entry id="A-001">Valid entry</entry>
|
||||
<entry id="B123">Invalid format</entry>
|
||||
<entry id="C-042">Another valid</entry>
|
||||
</entries>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/entries">
|
||||
<validated>
|
||||
<xsl:for-each select="entry">
|
||||
<entry valid="{if (matches(@id, '^[A-Z]-\d{{3}}$'), 'true', 'false')}">
|
||||
<xsl:value-of select="."/>
|
||||
</entry>
|
||||
</xsl:for-each>
|
||||
</validated>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<validated>
|
||||
<entry valid="true">Valid entry</entry>
|
||||
<entry valid="false">Invalid format</entry>
|
||||
<entry valid="true">Another valid</entry>
|
||||
</validated>
|
||||
```
|
||||
|
||||
*Note: inside attribute value templates, `{` and `}` must be doubled: `{{` and `}}`.*
|
||||
|
||||
### Case-insensitive search
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/entries">
|
||||
<matches>
|
||||
<xsl:for-each select="entry[matches(., 'valid', 'i')]">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</matches>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<matches>
|
||||
<item>Valid entry</item>
|
||||
<item>Invalid format</item>
|
||||
<item>Another valid</item>
|
||||
</matches>
|
||||
```
|
||||
|
||||
### Filter with a pattern predicate
|
||||
|
||||
```xml
|
||||
<!-- Select only elements whose text is a valid email-like pattern -->
|
||||
<xsl:for-each select="contact[matches(email, '^[^@]+@[^@]+\.[^@]+$')]">
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `matches()` is case-sensitive by default. Use the `i` flag for case-insensitive matching.
|
||||
- The regex is anchored only with `^` / `$` — without them, a partial match anywhere in the string returns `true`.
|
||||
- XPath regex does not support all PCRE features. Lookahead (`?=`), lookbehind (`?<=`), and named groups are not available.
|
||||
- In XSLT 1.0, there is no built-in regex support. The only alternative is complex template recursion or extension functions.
|
||||
|
||||
## See also
|
||||
|
||||
- [replace()](../xpath-replace)
|
||||
- [tokenize()](../xpath-tokenize)
|
||||
- [contains()](../xpath-contains)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: "position()"
|
||||
description: "Returns the position of the context node within the current node-set, starting at 1."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "position()"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`position()` returns an integer representing the **1-based position** of the current context node within the node-set being iterated. It takes no arguments.
|
||||
|
||||
It is most commonly used inside `xsl:for-each` or predicates to:
|
||||
|
||||
- Generate row numbers or sequence numbers in the output.
|
||||
- Apply alternating styles (odd/even rows).
|
||||
- Conditionally process only specific positions (first, last, every nth item).
|
||||
- Omit separators before or after specific items.
|
||||
|
||||
The context for `position()` is determined by the nearest enclosing iteration (`xsl:for-each`, `xsl:apply-templates`, or a predicate). Inside a predicate, `position()` refers to the position within the node-set being filtered, not the outer iteration.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer` — the 1-based position of the context node within the current context sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Row numbers in a table
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<employees>
|
||||
<employee><name>Alice</name></employee>
|
||||
<employee><name>Bob</name></employee>
|
||||
<employee><name>Carol</name></employee>
|
||||
</employees>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/employees">
|
||||
<table>
|
||||
<xsl:for-each select="employee">
|
||||
<row number="{position()}">
|
||||
<xsl:value-of select="name"/>
|
||||
</row>
|
||||
</xsl:for-each>
|
||||
</table>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<table>
|
||||
<row number="1">Alice</row>
|
||||
<row number="2">Bob</row>
|
||||
<row number="3">Carol</row>
|
||||
</table>
|
||||
```
|
||||
|
||||
### Odd/even row class
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/employees">
|
||||
<table>
|
||||
<xsl:for-each select="employee">
|
||||
<row class="{if(position() mod 2 = 0, 'even', 'odd')}">
|
||||
<xsl:value-of select="name"/>
|
||||
</row>
|
||||
</xsl:for-each>
|
||||
</table>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<table>
|
||||
<row class="odd">Alice</row>
|
||||
<row class="even">Bob</row>
|
||||
<row class="odd">Carol</row>
|
||||
</table>
|
||||
```
|
||||
|
||||
*Note: the `if()` expression requires XSLT 2.0. In XSLT 1.0, use `xsl:choose` instead.*
|
||||
|
||||
### Select every second element using a predicate
|
||||
|
||||
```xml
|
||||
<xsl:value-of select="employee[position() mod 2 = 1]/name" separator=", "/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `position()` inside a predicate `[position() = 1]` can be shortened to `[1]`.
|
||||
- The shorthand `item[last()]` selects the last item; `item[1]` selects the first.
|
||||
- Document order is used by default; if `xsl:sort` is present, positions reflect the sorted order.
|
||||
- Do not confuse `position()` with the numeric value of an `@id` attribute or similar content-based numbering — `position()` is purely about iteration order.
|
||||
|
||||
## See also
|
||||
|
||||
- [last()](../xpath-last)
|
||||
- [xsl:for-each](../xsl-for-each)
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
title: "replace()"
|
||||
description: "Replaces all substrings of a string that match a regular expression with a replacement string."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "replace(string, pattern, replacement, flags?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`replace()` searches the input string for all occurrences of the regular expression `pattern` and substitutes each match with the `replacement` string. Unlike `translate()` (which works character-by-character), `replace()` operates on substrings and patterns, making it suitable for complex string transformations.
|
||||
|
||||
The `replacement` string may include **back-references** to captured groups using `$1`, `$2`, etc., where `$0` refers to the entire matched substring. Dollar signs that are not back-references must be escaped as `\$`.
|
||||
|
||||
The function uses XPath regex syntax (a subset of XML Schema regex), which is similar to Java/Perl regex but does not support lookaheads or backreferences in the pattern itself.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string | Yes | The input string to perform replacements on. |
|
||||
| `pattern` | xs:string | Yes | Regular expression pattern matching the substrings to replace. |
|
||||
| `replacement` | xs:string | Yes | Replacement string; may use `$0`, `$1`, etc. for captured groups. |
|
||||
| `flags` | xs:string | No | Regex flags: `i` (case-insensitive), `m` (multiline), `s` (dot-all), `x` (extended). |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the input string with all matches of `pattern` replaced by `replacement`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Remove unwanted characters
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<prices>
|
||||
<price>$1,299.00</price>
|
||||
<price>$849.50</price>
|
||||
</prices>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/prices">
|
||||
<numbers>
|
||||
<xsl:for-each select="price">
|
||||
<!-- Remove $ and comma to get a plain number -->
|
||||
<number><xsl:value-of select="replace(., '[\$,]', '')"/></number>
|
||||
</xsl:for-each>
|
||||
</numbers>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<numbers>
|
||||
<number>1299.00</number>
|
||||
<number>849.50</number>
|
||||
</numbers>
|
||||
```
|
||||
|
||||
### Reformat a date using back-references
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<events>
|
||||
<event date="2026-04-18">Conference</event>
|
||||
<event date="2026-05-01">Workshop</event>
|
||||
</events>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/events">
|
||||
<events>
|
||||
<xsl:for-each select="event">
|
||||
<!-- Reformat YYYY-MM-DD to DD/MM/YYYY -->
|
||||
<event date="{replace(@date, '^(\d{{4}})-(\d{{2}})-(\d{{2}})$', '$3/$2/$1')}">
|
||||
<xsl:value-of select="."/>
|
||||
</event>
|
||||
</xsl:for-each>
|
||||
</events>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<events>
|
||||
<event date="18/04/2026">Conference</event>
|
||||
<event date="01/05/2026">Workshop</event>
|
||||
</events>
|
||||
```
|
||||
|
||||
*Note: curly braces inside attribute value templates must be doubled: `{{` and `}}`.*
|
||||
|
||||
### Collapse multiple spaces
|
||||
|
||||
```xml
|
||||
<xsl:value-of select="replace(normalize-space(description), '\s+', ' ')"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `replace()` replaces **all** occurrences, not just the first. There is no `replaceFirst()` equivalent in XPath.
|
||||
- To escape a literal `$` in the replacement string, write `\$`.
|
||||
- The pattern cannot match an empty string; if the pattern can match zero characters Saxon raises a dynamic error.
|
||||
- For simple character substitution, `translate()` (XSLT 1.0) is simpler and more efficient. Use `replace()` when you need pattern matching or back-references.
|
||||
- Inside attribute value templates, curly braces within the regex (e.g., `\d{4}`) must be doubled: `\d{{4}}`.
|
||||
|
||||
## See also
|
||||
|
||||
- [matches()](../xpath-matches)
|
||||
- [tokenize()](../xpath-tokenize)
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: "string-join()"
|
||||
description: "Joins a sequence of strings into a single string with a specified separator between each item."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "string-join(sequence, separator?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`string-join()` takes a sequence of strings and concatenates them into a single string, placing the separator between each consecutive pair of items. If the sequence contains only one item, no separator is added. If the sequence is empty, an empty string is returned.
|
||||
|
||||
The `separator` argument is optional in XPath 3.1; when omitted it defaults to an empty string (items are concatenated with no separator). In XPath 2.0 the separator argument is required.
|
||||
|
||||
`string-join()` is the idiomatic XSLT 2.0+ replacement for the XSLT 1.0 pattern of iterating with `xsl:for-each` and manually appending separators using `position() != last()`. It works on any sequence of atomic values (each is converted to a string) and on element text content via paths like `element/string()`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | xs:string* | Yes | The sequence of strings to join. Non-string items are converted to strings. |
|
||||
| `separator` | xs:string | No (XPath 3.1+) / Yes (XPath 2.0) | The string inserted between each pair of adjacent items. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — all items in the sequence joined by the separator.
|
||||
|
||||
## Examples
|
||||
|
||||
### Join element values with a comma
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tags>
|
||||
<tag>xslt</tag>
|
||||
<tag>xml</tag>
|
||||
<tag>xpath</tag>
|
||||
<tag>transformation</tag>
|
||||
</tags>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/tags">
|
||||
<xsl:value-of select="string-join(tag, ', ')"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
xslt, xml, xpath, transformation
|
||||
```
|
||||
|
||||
### Build a pipe-delimited list in an attribute
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/tags">
|
||||
<index keywords="{string-join(tag, '|')}"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<index keywords="xslt|xml|xpath|transformation"/>
|
||||
```
|
||||
|
||||
### Join string values from a sequence expression
|
||||
|
||||
```xml
|
||||
<!-- Join all unique category values found in a product catalog -->
|
||||
<xsl:value-of select="string-join(distinct-values(//product/category), ' / ')"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `string-join()` requires XSLT 2.0 or later. In XSLT 1.0, replicate the behaviour with `xsl:for-each` and a `position() != last()` conditional separator.
|
||||
- The function does not add a leading or trailing separator — only between items.
|
||||
- Non-string items in the sequence (numbers, booleans) are cast to `xs:string` before joining.
|
||||
- To join node string values, use the path expression directly: `string-join(item, ', ')` extracts each `item` element's text content automatically.
|
||||
|
||||
## See also
|
||||
|
||||
- [tokenize()](../xpath-tokenize)
|
||||
- [concat()](../xpath-concat)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: "substring()"
|
||||
description: "Extracts a portion of a string by start position and optional length, returning the resulting substring."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "string function"
|
||||
syntax: "substring(string, start, length?)"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`substring()` returns the portion of a string beginning at position `start` and extending for `length` characters. If `length` is omitted, the function returns all characters from `start` to the end of the string.
|
||||
|
||||
String positions in XPath are **1-based** (the first character is position 1). The `start` and `length` arguments are numbers; they are rounded to the nearest integer using the XPath rounding rules. If `start` is less than 1, the returned string effectively begins at position 1 (the excess is deducted from `length`).
|
||||
|
||||
`substring()` is the fundamental string-slicing function in XPath 1.0. For more complex extraction needs, consider `substring-before()` and `substring-after()`, which split on a delimiter without needing to know its position.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string | Yes | The source string to extract from. |
|
||||
| `start` | xs:double | Yes | 1-based position of the first character to include. |
|
||||
| `length` | xs:double | No | Number of characters to include. Defaults to the rest of the string. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the extracted substring.
|
||||
|
||||
## Examples
|
||||
|
||||
### Extract a fixed-length prefix
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<codes>
|
||||
<code>PROD-001-RED</code>
|
||||
<code>PROD-002-BLU</code>
|
||||
<code>PROD-003-GRN</code>
|
||||
</codes>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/codes">
|
||||
<ids>
|
||||
<xsl:for-each select="code">
|
||||
<!-- Extract characters 6 to 8 (the numeric ID) -->
|
||||
<id><xsl:value-of select="substring(., 6, 3)"/></id>
|
||||
</xsl:for-each>
|
||||
</ids>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<ids>
|
||||
<id>001</id>
|
||||
<id>002</id>
|
||||
<id>003</id>
|
||||
</ids>
|
||||
```
|
||||
|
||||
### Extract from a position to end of string
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/codes">
|
||||
<colors>
|
||||
<xsl:for-each select="code">
|
||||
<!-- Skip first 9 characters, get the rest -->
|
||||
<color><xsl:value-of select="substring(., 10)"/></color>
|
||||
</xsl:for-each>
|
||||
</colors>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<colors>
|
||||
<color>RED</color>
|
||||
<color>BLU</color>
|
||||
<color>GRN</color>
|
||||
</colors>
|
||||
```
|
||||
|
||||
### Capitalise first character (XSLT 2.0 pattern)
|
||||
|
||||
```xml
|
||||
<!-- Uppercase the first character, lowercase the rest -->
|
||||
<xsl:value-of select="concat(upper-case(substring(name, 1, 1)), lower-case(substring(name, 2)))"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- XPath string positions start at **1**, not 0. `substring('hello', 1, 3)` returns `"hel"`.
|
||||
- If `start + length` exceeds the string length, the result is simply truncated at the end of the string — no error is raised.
|
||||
- For delimiter-based splitting, `substring-before()` and `substring-after()` are more convenient than computing numeric positions.
|
||||
- In XSLT 2.0+, `replace()` with regex groups is often a cleaner way to extract structured parts of strings.
|
||||
|
||||
## See also
|
||||
|
||||
- [contains()](../xpath-contains)
|
||||
- [replace()](../xpath-replace)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "sum()"
|
||||
description: "Returns the sum of the numeric values in a node-set or sequence, or a specified zero value for empty sequences."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "numeric function"
|
||||
syntax: "sum(node-set)"
|
||||
tags: ["xslt", "reference", "xslt1", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`sum()` converts each node in a node-set to a number (using the XPath `number()` rules) and returns their total as a double. If any node cannot be converted to a number, its value is treated as `NaN`, and the entire result is `NaN`.
|
||||
|
||||
In XSLT 2.0+, `sum()` accepts any sequence of atomic values that can be added together. A second argument may be provided as a **zero value** to return when the sequence is empty (in XPath 1.0, `sum()` on an empty node-set returns `0`).
|
||||
|
||||
`sum()` is the standard way to compute totals over repeated elements, such as order amounts, quantities, or scores, without writing an explicit loop.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node-set` | node-set / sequence | Yes | The nodes or items to sum. Each is converted to a number. |
|
||||
| `zero` | atomic value | No | Value to return if the sequence is empty (XPath 2.0+). Defaults to `0`. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:double` (XPath 1.0) or the type matching the input sequence (XPath 2.0+) — the numeric sum of all items.
|
||||
|
||||
## Examples
|
||||
|
||||
### Sum all child element values
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<invoice>
|
||||
<line amount="29.99"/>
|
||||
<line amount="14.50"/>
|
||||
<line amount="5.00"/>
|
||||
</invoice>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/invoice">
|
||||
<xsl:text>Total: </xsl:text>
|
||||
<xsl:value-of select="sum(line/@amount)"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Total: 49.49
|
||||
```
|
||||
|
||||
### Conditional sum (sum filtered values)
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sales>
|
||||
<sale region="North" amount="100"/>
|
||||
<sale region="South" amount="250"/>
|
||||
<sale region="North" amount="175"/>
|
||||
<sale region="South" amount="80"/>
|
||||
</sales>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/sales">
|
||||
<totals>
|
||||
<north><xsl:value-of select="sum(sale[@region='North']/@amount)"/></north>
|
||||
<south><xsl:value-of select="sum(sale[@region='South']/@amount)"/></south>
|
||||
</totals>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<totals>
|
||||
<north>275</north>
|
||||
<south>330</south>
|
||||
</totals>
|
||||
```
|
||||
|
||||
### Empty sequence with fallback (XSLT 2.0)
|
||||
|
||||
```xml
|
||||
<!-- Returns 0 when there are no discount elements -->
|
||||
<xsl:value-of select="sum(discount/@value, 0)"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Nodes that cannot be converted to a number (e.g., text like `"N/A"`) produce `NaN`, which propagates through the sum. Validate data or use `number()` with a fallback before summing.
|
||||
- `sum()` on an empty node-set returns `0` in XPath 1.0. In XPath 2.0+, the second argument controls this behaviour.
|
||||
- For an average, there is no built-in `avg()` in XPath 1.0. Compute it as `sum(nodes) div count(nodes)`. XPath 2.0+ provides `avg()`.
|
||||
- `sum()` works on attribute nodes as well as element text nodes; the path `sum(items/item/@qty)` is valid.
|
||||
|
||||
## See also
|
||||
|
||||
- [count()](../xpath-count)
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: "tokenize()"
|
||||
description: "Splits a string into a sequence of substrings using a regular expression as the delimiter pattern."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "tokenize(string, pattern, flags?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`tokenize()` splits a string into a sequence of substrings wherever the `pattern` (a regular expression) matches. The matched delimiters are not included in the result. The function returns a sequence of `xs:string` items.
|
||||
|
||||
If the input string begins or ends with the delimiter pattern, the result includes an empty string at the start or end of the sequence respectively. If the input is an empty string and the pattern matches the empty string, the result is an empty sequence.
|
||||
|
||||
`tokenize()` is the inverse of `string-join()`: where `string-join()` assembles strings from a sequence, `tokenize()` disassembles a string into a sequence. This makes them natural complements for round-tripping delimited data.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string | Yes | The input string to split. |
|
||||
| `pattern` | xs:string | Yes | A regular expression matching the delimiter. |
|
||||
| `flags` | xs:string | No | Regex flags: `i` (case-insensitive), `m` (multiline), `s` (dot-all), `x` (extended). |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string*` — a sequence of substrings split at each match of `pattern`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Split a comma-separated list
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data>
|
||||
<csv>apple,banana,cherry,date</csv>
|
||||
</data>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<items>
|
||||
<xsl:for-each select="tokenize(csv, ',')">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</items>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<items>
|
||||
<item>apple</item>
|
||||
<item>banana</item>
|
||||
<item>cherry</item>
|
||||
<item>date</item>
|
||||
</items>
|
||||
```
|
||||
|
||||
### Split on whitespace
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<words>
|
||||
<!-- \s+ matches one or more whitespace characters -->
|
||||
<xsl:for-each select="tokenize(normalize-space(csv), '\s+')">
|
||||
<word><xsl:value-of select="."/></word>
|
||||
</xsl:for-each>
|
||||
</words>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
### Count tokens
|
||||
|
||||
```xml
|
||||
<!-- Count the number of comma-separated values -->
|
||||
<xsl:value-of select="count(tokenize(csv, ','))"/>
|
||||
```
|
||||
|
||||
### Access a specific token by position
|
||||
|
||||
```xml
|
||||
<!-- Get the second CSV field -->
|
||||
<xsl:value-of select="tokenize(csv, ',')[2]"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The `pattern` argument is a regular expression, not a plain string. Characters like `.`, `*`, `+`, `?`, `(`, `)` must be escaped with `\` if used literally (e.g., to split on a literal `.`, use `'\.'`).
|
||||
- `tokenize()` returns zero or more strings; iterate the result with `xsl:for-each` or index it with `[n]`.
|
||||
- If `pattern` can match an empty string (e.g., `'.*'`), Saxon raises an error — the delimiter must have non-zero length.
|
||||
- For simple fixed-character splitting (comma, pipe), `tokenize()` is the idiomatic choice in XSLT 2.0+. In XSLT 1.0, use recursive named templates.
|
||||
|
||||
## See also
|
||||
|
||||
- [matches()](../xpath-matches)
|
||||
- [string-join()](../xpath-string-join)
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
title: "xsl:for-each-group"
|
||||
description: "Groups a sequence of items by a key expression or adjacent values, then iterates over each distinct group."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "element"
|
||||
syntax: '<xsl:for-each-group select="sequence" group-by="expression">'
|
||||
tags: ["xslt", "reference", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`xsl:for-each-group` divides a sequence into groups and then processes each group once. It replaces the complex Muenchian grouping technique required in XSLT 1.0 with a clean, declarative approach.
|
||||
|
||||
There are four mutually exclusive grouping attributes:
|
||||
|
||||
- **`group-by`** — groups items that share the same value of the key expression (like SQL `GROUP BY`).
|
||||
- **`group-adjacent`** — groups consecutive items with the same key value.
|
||||
- **`group-starting-with`** — starts a new group whenever an item matches a pattern.
|
||||
- **`group-ending-with`** — ends the current group whenever an item matches a pattern.
|
||||
|
||||
Inside the loop body, `current-group()` returns the sequence of items in the current group, and `current-grouping-key()` returns the key value that defines the group (available with `group-by` and `group-adjacent`).
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `select` | XPath expression | Yes | The sequence to be grouped. |
|
||||
| `group-by` | XPath expression | No* | Key expression evaluated for each item; items with equal keys form a group. |
|
||||
| `group-adjacent` | XPath expression | No* | Like `group-by` but only consecutive equal-key items are grouped. |
|
||||
| `group-starting-with` | Pattern | No* | A new group begins each time an item matches the pattern. |
|
||||
| `group-ending-with` | Pattern | No* | A group ends each time an item matches the pattern. |
|
||||
| `collation` | URI | No | Collation used for key comparison. |
|
||||
|
||||
*Exactly one grouping attribute must be present.
|
||||
|
||||
## Examples
|
||||
|
||||
### Group items by category
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<products>
|
||||
<product><name>Apple</name><category>Fruit</category></product>
|
||||
<product><name>Carrot</name><category>Vegetable</category></product>
|
||||
<product><name>Banana</name><category>Fruit</category></product>
|
||||
<product><name>Broccoli</name><category>Vegetable</category></product>
|
||||
<product><name>Cherry</name><category>Fruit</category></product>
|
||||
</products>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/products">
|
||||
<grouped>
|
||||
<xsl:for-each-group select="product" group-by="category">
|
||||
<xsl:sort select="current-grouping-key()"/>
|
||||
<group name="{current-grouping-key()}">
|
||||
<xsl:for-each select="current-group()">
|
||||
<item><xsl:value-of select="name"/></item>
|
||||
</xsl:for-each>
|
||||
</group>
|
||||
</xsl:for-each-group>
|
||||
</grouped>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<grouped>
|
||||
<group name="Fruit">
|
||||
<item>Apple</item>
|
||||
<item>Banana</item>
|
||||
<item>Cherry</item>
|
||||
</group>
|
||||
<group name="Vegetable">
|
||||
<item>Carrot</item>
|
||||
<item>Broccoli</item>
|
||||
</group>
|
||||
</grouped>
|
||||
```
|
||||
|
||||
### Group adjacent elements (section headings)
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doc>
|
||||
<h1>Introduction</h1>
|
||||
<p>First paragraph.</p>
|
||||
<p>Second paragraph.</p>
|
||||
<h1>Conclusion</h1>
|
||||
<p>Final paragraph.</p>
|
||||
</doc>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/doc">
|
||||
<sections>
|
||||
<xsl:for-each-group select="*" group-starting-with="h1">
|
||||
<section>
|
||||
<title><xsl:value-of select="self::h1"/></title>
|
||||
<xsl:for-each select="current-group()[not(self::h1)]">
|
||||
<para><xsl:value-of select="."/></para>
|
||||
</xsl:for-each>
|
||||
</section>
|
||||
</xsl:for-each-group>
|
||||
</sections>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<sections>
|
||||
<section>
|
||||
<title>Introduction</title>
|
||||
<para>First paragraph.</para>
|
||||
<para>Second paragraph.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Conclusion</title>
|
||||
<para>Final paragraph.</para>
|
||||
</section>
|
||||
</sections>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `current-group()` is only accessible inside the body of `xsl:for-each-group`.
|
||||
- `xsl:sort` applies to the order of **groups**, not to the items within each group. Sort items inside `xsl:for-each select="current-group()"` separately.
|
||||
- Multiple grouping keys can be achieved by nesting `xsl:for-each-group` elements.
|
||||
- For XSLT 1.0, the equivalent technique is the Muenchian method using `xsl:key` and `generate-id()`. See the [XSLT grouping guide](/posts/xslt-grouping-for-each-group).
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:for-each](../xsl-for-each)
|
||||
- [key()](../xpath-key)
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: "xsl:for-each"
|
||||
description: "Iterates over a node-set or sequence, applying the contained template body to each item in document order."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "element"
|
||||
syntax: "<xsl:for-each select=\"node-set\">"
|
||||
tags: ["xslt", "reference", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`xsl:for-each` selects a set of nodes (or, in XSLT 2.0+, a sequence of items) and processes each one in turn. Within the loop body, the **context node** changes to the current item, so XPath expressions are evaluated relative to it.
|
||||
|
||||
It is the standard way to iterate over child elements or any repeated node structure when you do not want to use recursive template matching. The loop body can contain any sequence of XSLT instructions: output elements, `xsl:value-of`, nested `xsl:for-each` calls, conditionals, and so on.
|
||||
|
||||
An optional `xsl:sort` child element placed immediately inside `xsl:for-each` (before any other content) changes the processing order without altering the source document.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `select` | XPath expression | Yes | Node-set or sequence to iterate over. |
|
||||
|
||||
### Child element: `xsl:sort`
|
||||
|
||||
Place one or more `xsl:sort` elements as the first children to sort the selected set before processing.
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `select` | XPath expression used as the sort key. |
|
||||
| `order` | `"ascending"` (default) or `"descending"`. |
|
||||
| `data-type` | `"text"` (default) or `"number"`. |
|
||||
|
||||
## Examples
|
||||
|
||||
### Iterate over child elements
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<catalog>
|
||||
<item id="1"><name>Widget</name><price>9.99</price></item>
|
||||
<item id="2"><name>Gadget</name><price>24.99</price></item>
|
||||
<item id="3"><name>Doohickey</name><price>4.49</price></item>
|
||||
</catalog>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/catalog">
|
||||
<ul>
|
||||
<xsl:for-each select="item">
|
||||
<li>
|
||||
<xsl:value-of select="name"/>
|
||||
<xsl:text> — $</xsl:text>
|
||||
<xsl:value-of select="price"/>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<ul>
|
||||
<li>Widget — $9.99</li>
|
||||
<li>Gadget — $24.99</li>
|
||||
<li>Doohickey — $4.49</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
### Sorted iteration
|
||||
|
||||
**Stylesheet (sort by price descending):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/catalog">
|
||||
<ul>
|
||||
<xsl:for-each select="item">
|
||||
<xsl:sort select="price" data-type="number" order="descending"/>
|
||||
<li>
|
||||
<xsl:value-of select="concat(name, ' — $', price)"/>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<ul>
|
||||
<li>Gadget — $24.99</li>
|
||||
<li>Widget — $9.99</li>
|
||||
<li>Doohickey — $4.49</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `position()` and `last()` inside the loop refer to the position within the selected set, not the original document position.
|
||||
- `current()` inside the loop returns the same node as `.` (the context node). It becomes useful when `current()` is called inside a predicate.
|
||||
- For grouping scenarios (e.g., group items by category) prefer `xsl:for-each-group` (XSLT 2.0+) over the Muenchian method with `xsl:for-each`.
|
||||
- Template rules (`xsl:apply-templates`) are generally more flexible and reusable than `xsl:for-each`; use `xsl:for-each` when the transformation logic is short and self-contained.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:for-each-group](../xsl-for-each-group)
|
||||
- [position()](../xpath-position)
|
||||
- [last()](../xpath-last)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: "xsl:function"
|
||||
description: "Defines a named, callable stylesheet function available in XPath expressions throughout the stylesheet."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "element"
|
||||
syntax: '<xsl:function name="prefix:name" as="return-type">'
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`xsl:function` lets you define reusable functions directly inside a stylesheet. Once declared, the function can be called from any XPath expression in the same stylesheet — in `select` attributes, predicates, pattern expressions, or attribute value templates.
|
||||
|
||||
Functions must have a **namespace-qualified name** (a prefix other than `xsl:`). The `as` attribute declares the return type using an XPath sequence type such as `xs:string`, `xs:integer`, `element()`, or `xs:string*`. Parameters are declared with `xsl:param` child elements, each optionally carrying an `as` type constraint.
|
||||
|
||||
Unlike named templates (`xsl:call-template`), stylesheet functions return a value and can be used inline inside XPath expressions. They cannot produce result-tree nodes as a side effect — the function body must evaluate to a sequence that becomes the return value.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | QName | Yes | The qualified name of the function (must include a non-`xsl:` namespace prefix). |
|
||||
| `as` | SequenceType | No | Declared return type. Saxon enforces type checking when specified. |
|
||||
| `visibility` | `"public"` \| `"private"` \| `"final"` \| `"abstract"` | No | Controls visibility in package/module scenarios (XSLT 3.0). Defaults to `"private"`. |
|
||||
| `override` | `"yes"` \| `"no"` | No | XSLT 2.0 only: whether this function overrides an imported function with the same name and arity. |
|
||||
|
||||
### Child elements
|
||||
|
||||
| Element | Description |
|
||||
|---------|-------------|
|
||||
| `xsl:param` | Declares a parameter. Add one per argument in signature order. |
|
||||
| *(body instructions)* | Any XSLT instructions whose final evaluated result is the function's return value. |
|
||||
|
||||
## Return value
|
||||
|
||||
The return value is whatever the last instruction in the function body evaluates to, or whatever is returned by `xsl:sequence`. The type is validated against the `as` attribute if present.
|
||||
|
||||
## Examples
|
||||
|
||||
### String utility function
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fn="http://example.com/functions"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
exclude-result-prefixes="fn xs">
|
||||
|
||||
<!-- Custom function: capitalise the first letter of a string -->
|
||||
<xsl:function name="fn:capitalize" as="xs:string">
|
||||
<xsl:param name="input" as="xs:string"/>
|
||||
<xsl:sequence select="concat(upper-case(substring($input, 1, 1)), substring($input, 2))"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/names">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
<result>
|
||||
<xsl:for-each select="name">
|
||||
<item><xsl:value-of select="fn:capitalize(.)"/></item>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<names>
|
||||
<name>alice</name>
|
||||
<name>bob</name>
|
||||
<name>carol</name>
|
||||
</names>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<item>Alice</item>
|
||||
<item>Bob</item>
|
||||
<item>Carol</item>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Function using string-join
|
||||
|
||||
**Stylesheet (join a sequence with a custom delimiter):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:util="http://example.com/util"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
exclude-result-prefixes="util xs">
|
||||
|
||||
<xsl:function name="util:join-tags" as="xs:string">
|
||||
<xsl:param name="items" as="xs:string*"/>
|
||||
<xsl:sequence select="string-join($items, ' | ')"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/article">
|
||||
<xsl:output method="text"/>
|
||||
<xsl:value-of select="util:join-tags(tags/tag/string())"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Function names must use a non-empty namespace prefix. `xsl:function name="myFunc"` is invalid.
|
||||
- Recursive calls are supported and commonly used for tree-walking functions.
|
||||
- XSLT 3.0 introduces higher-order functions — `xsl:function` can be referenced as a value with `function-lookup()` or passed as an argument.
|
||||
- Type annotations (`as` on `xsl:param` and `xsl:function`) improve both performance and early error detection in Saxon.
|
||||
|
||||
## See also
|
||||
|
||||
- [string-join()](../xpath-string-join)
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
title: "xsl:iterate"
|
||||
description: "Processes a sequence item-by-item with carry-forward parameters, enabling efficient streaming and stateful iteration in XSLT 3.0."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "element"
|
||||
syntax: "<xsl:iterate select=\"sequence\">"
|
||||
tags: ["xslt", "reference", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`xsl:iterate` is an XSLT 3.0 instruction that processes a sequence one item at a time, similar to `xsl:for-each`, but with two important additions:
|
||||
|
||||
1. **Carry-forward parameters** — declared with `xsl:param` inside the instruction, updated at the end of each iteration via `xsl:next-iteration`, and available in the final result via `xsl:on-completion`.
|
||||
2. **Early termination** — `xsl:break` stops iteration before the end of the sequence, optionally emitting output at that point.
|
||||
|
||||
These features make `xsl:iterate` the right tool for running aggregations (cumulative totals, maximums, etc.), building state across items, or stopping as soon as a condition is met. It also works in **streaming mode** (`xsl:stream`) because it processes the sequence without needing to hold it all in memory simultaneously.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `select` | XPath expression | Yes | The sequence to iterate over. |
|
||||
|
||||
### Child elements
|
||||
|
||||
| Element | Description |
|
||||
|---------|-------------|
|
||||
| `xsl:param` | Declares a carry-forward parameter with an initial value. |
|
||||
| `xsl:next-iteration` | Provides updated parameter values for the next iteration. Must be the last instruction in the body (or inside `xsl:break`). |
|
||||
| `xsl:on-completion` | Body executed after the last item (or after `xsl:break`). Has access to the final carry-forward parameter values. |
|
||||
| `xsl:break` | Terminates the iteration immediately; can contain `xsl:on-completion` inline. |
|
||||
|
||||
## Return value
|
||||
|
||||
The instruction produces the nodes/items written by its body instructions and by `xsl:on-completion`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Running total
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<orders>
|
||||
<order amount="120.00"/>
|
||||
<order amount="45.50"/>
|
||||
<order amount="200.00"/>
|
||||
<order amount="33.25"/>
|
||||
</orders>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/orders">
|
||||
<xsl:iterate select="order">
|
||||
<xsl:param name="total" as="xs:decimal" select="0"/>
|
||||
<xsl:next-iteration>
|
||||
<xsl:with-param name="total" select="$total + xs:decimal(@amount)"/>
|
||||
</xsl:next-iteration>
|
||||
<xsl:on-completion>
|
||||
<summary>
|
||||
<total><xsl:value-of select="$total"/></total>
|
||||
</summary>
|
||||
</xsl:on-completion>
|
||||
</xsl:iterate>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<summary>
|
||||
<total>398.75</total>
|
||||
</summary>
|
||||
```
|
||||
|
||||
### Stop at first match
|
||||
|
||||
**Stylesheet (find the first order over 100):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/orders">
|
||||
<xsl:iterate select="order">
|
||||
<xsl:choose>
|
||||
<xsl:when test="xs:decimal(@amount) gt 100">
|
||||
<xsl:break>
|
||||
<first-large-order amount="{@amount}"/>
|
||||
</xsl:break>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:iterate>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<first-large-order amount="120.00"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `xsl:iterate` requires XSLT 3.0. Use `xsl:for-each` for XSLT 1.0/2.0 iteration without carry-forward state.
|
||||
- The `xsl:next-iteration` instruction must appear as the last step of the loop body; any instructions after it are not executed.
|
||||
- `xsl:on-completion` sees the parameter values from the **last completed** iteration (or initial values if the sequence was empty).
|
||||
- When used with `xsl:stream`, the select sequence can be a document node read in streaming fashion, processing arbitrarily large files in bounded memory.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:for-each](../xsl-for-each)
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: "xsl:value-of"
|
||||
description: "Outputs the string value of an XPath expression as a text node in the result tree."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "element"
|
||||
syntax: '<xsl:value-of select="expression" disable-output-escaping="no"/>'
|
||||
tags: ["xslt", "reference", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`xsl:value-of` evaluates an XPath expression and writes its string value as a text node into the result tree. It is one of the most frequently used XSLT instructions and the primary way to copy data from the source XML into the output.
|
||||
|
||||
When the `select` expression returns a node-set, only the string value of the **first** node is used in XSLT 1.0. In XSLT 2.0 and later the result is a sequence, and all items are concatenated with a single space separator by default (or with the separator specified by the `separator` attribute).
|
||||
|
||||
The optional `disable-output-escaping` attribute, when set to `yes`, writes the text without escaping characters like `<` and `&`. This is rarely needed and can produce invalid XML; avoid it unless you have a specific requirement such as injecting pre-built HTML markup.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `select` | XPath expression | Yes | Expression whose string value is written to the output. |
|
||||
| `disable-output-escaping` | `"yes"` \| `"no"` | No | Defaults to `"no"`. When `"yes"`, special characters are not escaped. Use with care. |
|
||||
| `separator` | string (XSLT 2.0+) | No | String placed between items when the sequence contains more than one item. Defaults to a single space. |
|
||||
|
||||
## Return value
|
||||
|
||||
Produces a text node in the result tree. The instruction itself has no XPath return value.
|
||||
|
||||
## Examples
|
||||
|
||||
### Output a single element value
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<book>
|
||||
<title>Learning XSLT</title>
|
||||
<author>Jane Smith</author>
|
||||
</book>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/book">
|
||||
<xsl:value-of select="title"/>
|
||||
<xsl:text> by </xsl:text>
|
||||
<xsl:value-of select="author"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Learning XSLT by Jane Smith
|
||||
```
|
||||
|
||||
### Concatenate all items (XSLT 2.0)
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tags>
|
||||
<tag>xslt</tag>
|
||||
<tag>xml</tag>
|
||||
<tag>xpath</tag>
|
||||
</tags>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/tags">
|
||||
<xsl:value-of select="tag" separator=", "/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
xslt, xml, xpath
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- In XSLT 1.0, if `select` returns a node-set with multiple nodes, only the first node's string value is output. Use `xsl:for-each` to iterate all nodes.
|
||||
- The `separator` attribute was introduced in XSLT 2.0 and is not available in 1.0 stylesheets.
|
||||
- To produce an attribute value, use `xsl:attribute` with a value template `{expression}` instead of `xsl:value-of`.
|
||||
- `xsl:copy-of` preserves nodes including their type; use it when you need to copy nodes rather than their string representation.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:for-each](../xsl-for-each)
|
||||
- [concat()](../xpath-concat)
|
||||
@@ -35,6 +35,11 @@ publisher = "xsltplaygroundcom"
|
||||
url = "/about/"
|
||||
weight = 3
|
||||
|
||||
[[menu.main]]
|
||||
name = "Reference"
|
||||
url = "/xslt/functions/"
|
||||
weight = 4
|
||||
|
||||
[[menu.main]]
|
||||
name = "Charts"
|
||||
url = "https://alexandrev.github.io/xslt-lab/index.yaml"
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{{ define "main" }}
|
||||
<div class="page-header">
|
||||
<h1>XSLT & XPath Function Reference</h1>
|
||||
<p class="lead">Complete reference for XSLT elements and XPath functions, organized by version. Each entry includes syntax, parameters, and runnable examples.</p>
|
||||
</div>
|
||||
|
||||
{{ $elements := where .Pages "Params.category" "element" }}
|
||||
{{ $functions := where .Pages "Params.category" "ne" "element" }}
|
||||
|
||||
{{ if $elements }}
|
||||
<section class="ref-section">
|
||||
<h2>XSLT Elements</h2>
|
||||
<ul class="ref-index-list">
|
||||
{{ range $elements }}
|
||||
<li>
|
||||
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
|
||||
{{ with .Params.versionLabel }}<span class="ref-badge ref-badge--sm">{{ . }}</span>{{ end }}
|
||||
<span class="muted">{{ .Description | truncate 80 }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</section>
|
||||
{{ end }}
|
||||
|
||||
{{ if $functions }}
|
||||
<section class="ref-section">
|
||||
<h2>XPath Functions</h2>
|
||||
<ul class="ref-index-list">
|
||||
{{ range $functions }}
|
||||
<li>
|
||||
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
|
||||
{{ with .Params.versionLabel }}<span class="ref-badge ref-badge--sm">{{ . }}</span>{{ end }}
|
||||
<span class="muted">{{ .Description | truncate 80 }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</section>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,26 @@
|
||||
{{ define "main" }}
|
||||
<article class="post ref-page">
|
||||
<p class="eyebrow">XSLT Reference</p>
|
||||
<h1>{{ .Title }}</h1>
|
||||
<div class="ref-meta">
|
||||
{{ with .Params.versionLabel }}<span class="ref-badge">{{ . }}</span>{{ end }}
|
||||
{{ with .Params.category }}<span class="ref-badge ref-badge--cat">{{ . }}</span>{{ end }}
|
||||
</div>
|
||||
{{ with .Description }}<p class="lead">{{ . }}</p>{{ end }}
|
||||
{{ with .Params.syntax }}
|
||||
<div class="ref-syntax">
|
||||
<span class="ref-syntax-label">Syntax</span>
|
||||
<pre><code>{{ . }}</code></pre>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ partial "adsense/in-article.html" . }}
|
||||
<div class="content">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
<div class="ref-try">
|
||||
<a href="https://xsltplayground.com/" class="button" target="_blank" rel="noopener noreferrer">Try it in XSLT Playground →</a>
|
||||
</div>
|
||||
<p class="muted back-link"><a href="{{ .CurrentSection.RelPermalink }}">← Back to XSLT Reference</a></p>
|
||||
{{ partial "related-posts.html" . }}
|
||||
</article>
|
||||
{{ end }}
|
||||
@@ -297,8 +297,141 @@ code {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── Reference pages ───────────────────────────────────────────── */
|
||||
|
||||
.ref-meta {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin: 10px 0 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ref-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
background: rgba(50, 213, 255, 0.12);
|
||||
color: var(--accent);
|
||||
border: 1px solid rgba(50, 213, 255, 0.25);
|
||||
}
|
||||
|
||||
.ref-badge--cat {
|
||||
background: rgba(255, 126, 103, 0.12);
|
||||
color: var(--accent-2);
|
||||
border-color: rgba(255, 126, 103, 0.25);
|
||||
}
|
||||
|
||||
.ref-badge--sm {
|
||||
font-size: 10px;
|
||||
padding: 1px 7px;
|
||||
}
|
||||
|
||||
.ref-syntax {
|
||||
margin: 20px 0;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ref-syntax-label {
|
||||
display: block;
|
||||
padding: 6px 14px;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.ref-syntax pre {
|
||||
margin: 0;
|
||||
padding: 14px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.ref-syntax pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.ref-try {
|
||||
margin: 32px 0 24px;
|
||||
}
|
||||
|
||||
.ref-index-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 32px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.ref-index-list li {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 10px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ref-index-list li:hover {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
|
||||
.ref-index-list a {
|
||||
font-weight: 600;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.ref-section {
|
||||
margin: 32px 0;
|
||||
}
|
||||
|
||||
.ref-section h2 {
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.post.ref-page .content table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.post.ref-page .content th,
|
||||
.post.ref-page .content td {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--border);
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.post.ref-page .content th {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: var(--muted);
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* ── Media queries ─────────────────────────────────────────────── */
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.header-grid { grid-template-columns: 1fr; }
|
||||
.nav { flex-wrap: wrap; }
|
||||
.post-list li { flex-direction: column; align-items: flex-start; }
|
||||
.ref-index-list a { min-width: unset; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user