mirror of
https://github.com/alexandrev/xslt-lab.git
synced 2026-09-16 18:23:16 +00:00
feat(blog): complete XSLT/XPath reference — 229 function pages
Full coverage of XSLT 1.0, 2.0 and 3.0 elements and XPath functions: - 59 XSLT elements (xsl:stylesheet → xsl:use-accumulators) - 170 XPath functions (1.0 node/string/numeric/boolean, 2.0 sequence/ date/QName/string, 3.0 HOF/map/array/JSON/streaming) Each page: description, parameters table, return value, 2 runnable Saxon examples with input XML + stylesheet + output, notes, cross-links. xsltCompletions.js: all 229 entries now have blogSlug for hover links. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: "abs()"
|
||||
description: "Returns the absolute value of a numeric argument, removing any negative sign while preserving the numeric type."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "numeric function"
|
||||
syntax: "abs(number)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`abs()` returns the absolute (non-negative) value of its argument. The result has the same type as the input: `xs:integer` in gives `xs:integer` out, `xs:double` in gives `xs:double` out. If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `number` | xs:numeric? | Yes | The numeric value whose absolute value is required. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:numeric?` — same type and precision as the input, but non-negative. Returns the empty sequence if the argument is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Absolute value of a negative attribute
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<measurements>
|
||||
<value>-42</value>
|
||||
<value>17</value>
|
||||
<value>-3.14</value>
|
||||
</measurements>
|
||||
```
|
||||
|
||||
**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="/measurements">
|
||||
<absolutes>
|
||||
<xsl:for-each select="value">
|
||||
<abs><xsl:value-of select="abs(xs:decimal(.))"/></abs>
|
||||
</xsl:for-each>
|
||||
</absolutes>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<absolutes>
|
||||
<abs>42</abs>
|
||||
<abs>17</abs>
|
||||
<abs>3.14</abs>
|
||||
</absolutes>
|
||||
```
|
||||
|
||||
### Computing deviation from a target value
|
||||
|
||||
**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="/measurements">
|
||||
<deviations>
|
||||
<xsl:variable name="target" select="xs:decimal(10)"/>
|
||||
<xsl:for-each select="value">
|
||||
<deviation><xsl:value-of select="abs(xs:decimal(.) - $target)"/></deviation>
|
||||
</xsl:for-each>
|
||||
</deviations>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (for values -42, 17, -3.14 against target 10):**
|
||||
```xml
|
||||
<deviations>
|
||||
<deviation>52</deviation>
|
||||
<deviation>7</deviation>
|
||||
<deviation>13.14</deviation>
|
||||
</deviations>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `abs()` is defined in XPath 2.0 and is not available in XSLT 1.0. In XSLT 1.0, absolute value required a workaround such as `translate(., '-', '')` or a conditional expression.
|
||||
- The function preserves numeric type: `abs(xs:float(-1.0))` returns `xs:float(1.0)`.
|
||||
- `abs(xs:double('NaN'))` returns `NaN`; `abs(xs:double('-INF'))` returns `INF`.
|
||||
|
||||
## See also
|
||||
|
||||
- [avg()](../xpath-avg)
|
||||
- [min()](../xpath-min)
|
||||
- [max()](../xpath-max)
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "accumulator-after()"
|
||||
description: "Returns the value of a named accumulator computed after processing the current node in streaming mode."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "accumulator-after(name)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`accumulator-after()` returns the value of a named accumulator as computed just after all accumulator rules for the current node have been applied. It is the counterpart to `accumulator-before()`: where `accumulator-before()` gives the value before the node's rule fires, `accumulator-after()` gives the updated value reflecting the current node's contribution.
|
||||
|
||||
The function is only meaningful in contexts where an accumulator rule for the named accumulator has a match for the current node. If no rule matches, before and after values are identical.
|
||||
|
||||
Both accumulator functions are essential for streaming transformations where you cannot revisit nodes. They allow you to carry state forward through the document without storing nodes in memory.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | xs:string | Yes | The name of the accumulator to read. |
|
||||
|
||||
## Return value
|
||||
|
||||
The declared return type of the named accumulator — the value computed after the current node's accumulator rule has been applied.
|
||||
|
||||
## Examples
|
||||
|
||||
### Cumulative total after each node
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<transactions>
|
||||
<tx amount="50"/>
|
||||
<tx amount="120"/>
|
||||
<tx amount="30"/>
|
||||
</transactions>
|
||||
```
|
||||
|
||||
**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:accumulator name="total" initial-value="xs:decimal(0)">
|
||||
<xsl:accumulator-rule match="tx" select="$value + xs:decimal(@amount)"/>
|
||||
</xsl:accumulator>
|
||||
|
||||
<xsl:template match="/transactions">
|
||||
<ledger>
|
||||
<xsl:apply-templates select="tx" use-accumulators="total"/>
|
||||
</ledger>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="tx" use-accumulators="total">
|
||||
<entry amount="{@amount}" running-total="{accumulator-after('total')}"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<ledger>
|
||||
<entry amount="50" running-total="50"/>
|
||||
<entry amount="120" running-total="170"/>
|
||||
<entry amount="30" running-total="200"/>
|
||||
</ledger>
|
||||
```
|
||||
|
||||
### Final accumulator value on the parent
|
||||
|
||||
**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:accumulator name="total" initial-value="xs:decimal(0)">
|
||||
<xsl:accumulator-rule match="tx" select="$value + xs:decimal(@amount)"/>
|
||||
</xsl:accumulator>
|
||||
|
||||
<xsl:template match="/transactions" use-accumulators="total">
|
||||
<xsl:apply-templates select="tx"/>
|
||||
<grand-total><xsl:value-of select="accumulator-after('total')"/></grand-total>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="tx"/>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<grand-total>200</grand-total>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `accumulator-after()` on a node with no matching accumulator rule returns the same value as `accumulator-before()`.
|
||||
- Accumulators must be listed in the `use-accumulators` attribute of the template or `xsl:use-accumulators` instruction to be active for that template.
|
||||
- Accumulators are phase-ordered: all accumulator rules are applied before any template generates output for a given node.
|
||||
- In XSLT 3.0 packages, accumulators can be imported and their visibility controlled with `xsl:expose`.
|
||||
|
||||
## See also
|
||||
|
||||
- [accumulator-before()](../xpath-accumulator-before)
|
||||
- [snapshot()](../xpath-snapshot)
|
||||
- [xsl:use-accumulators](../xsl-use-accumulators)
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "accumulator-before()"
|
||||
description: "Returns the value of a named accumulator computed before processing the current node in streaming mode."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "accumulator-before(name)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`accumulator-before()` returns the value of a named accumulator as it was just before the current node was processed. Accumulators are XSLT 3.0 constructs that compute running values as the processor traverses a document — similar to a running total or state machine. The "before" value reflects the accumulator state prior to applying any accumulator rule for the current node.
|
||||
|
||||
The function is used inside `xsl:accumulator-rule` actions and in template rules that access accumulator state. The `name` argument is a string literal matching the `name` attribute of an `xsl:accumulator` declaration.
|
||||
|
||||
For the function to be available in a template, the template must declare the accumulator in its `use-accumulators` attribute (or via `xsl:use-accumulators`).
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | xs:string | Yes | The name of the accumulator to read. |
|
||||
|
||||
## Return value
|
||||
|
||||
The declared return type of the named accumulator — the value computed just before the current node is entered.
|
||||
|
||||
## Examples
|
||||
|
||||
### Running total accumulator
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sales>
|
||||
<sale amount="100"/>
|
||||
<sale amount="250"/>
|
||||
<sale amount="75"/>
|
||||
</sales>
|
||||
```
|
||||
|
||||
**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:accumulator name="running-total" initial-value="xs:decimal(0)">
|
||||
<xsl:accumulator-rule match="sale" select="$value + xs:decimal(@amount)"/>
|
||||
</xsl:accumulator>
|
||||
|
||||
<xsl:template match="/sales">
|
||||
<report>
|
||||
<xsl:apply-templates select="sale" use-accumulators="running-total"/>
|
||||
</report>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="sale" use-accumulators="running-total">
|
||||
<sale amount="{@amount}" before="{accumulator-before('running-total')}"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<report>
|
||||
<sale amount="100" before="0"/>
|
||||
<sale amount="250" before="100"/>
|
||||
<sale amount="75" before="350"/>
|
||||
</report>
|
||||
```
|
||||
|
||||
### Comparing before and after values
|
||||
|
||||
**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:accumulator name="count" initial-value="xs:integer(0)">
|
||||
<xsl:accumulator-rule match="sale" select="$value + 1"/>
|
||||
</xsl:accumulator>
|
||||
|
||||
<xsl:template match="/sales">
|
||||
<xsl:apply-templates select="sale" use-accumulators="count"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="sale" use-accumulators="count">
|
||||
<item seq-before="{accumulator-before('count')}" seq-after="{accumulator-after('count')}"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<item seq-before="0" seq-after="1"/>
|
||||
<item seq-before="1" seq-after="2"/>
|
||||
<item seq-before="2" seq-after="3"/>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `accumulator-before()` reads the accumulator value before the node's rule fires; `accumulator-after()` reads it after.
|
||||
- The accumulator must be declared with `xsl:accumulator` at the top level and listed in the template's `use-accumulators` attribute.
|
||||
- Accumulators are primarily designed for streaming, but they also work in non-streaming transformations.
|
||||
- The initial value is used as the "before" value for the first matched node.
|
||||
|
||||
## See also
|
||||
|
||||
- [accumulator-after()](../xpath-accumulator-after)
|
||||
- [snapshot()](../xpath-snapshot)
|
||||
- [xsl:use-accumulators](../xsl-use-accumulators)
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: "apply()"
|
||||
description: "Calls a function item with arguments supplied as an array, enabling dynamic dispatch with a variable argument list."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "apply(function, array-of-args)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`apply()` invokes a function item, passing its arguments as members of an array. This enables dynamic function calls where both the function and its argument list are determined at runtime. The number of array members must match the arity of the function, otherwise a type error is raised.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `function` | function(*) | Yes | The function item to invoke. |
|
||||
| `array-of-args` | array(*) | Yes | An array whose members are the arguments to pass. Member count must equal the function arity. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the result returned by the invoked function.
|
||||
|
||||
## Examples
|
||||
|
||||
### Dynamic dispatch with apply()
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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"
|
||||
xmlns:f="http://example.com/functions">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:function name="f:add" as="xs:integer">
|
||||
<xsl:param name="a" as="xs:integer"/>
|
||||
<xsl:param name="b" as="xs:integer"/>
|
||||
<xsl:sequence select="$a + $b"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/">
|
||||
<result>
|
||||
<!-- Call f:add with arguments [3, 7] supplied as an array -->
|
||||
<xsl:variable name="fn" select="f:add#2"/>
|
||||
<xsl:variable name="args" select="[3, 7]"/>
|
||||
<value><xsl:value-of select="apply($fn, $args)"/></value>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<value>10</value>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Applying a selected operation dynamically
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<operations>
|
||||
<op name="upper" value="hello"/>
|
||||
<op name="lower" value="WORLD"/>
|
||||
</operations>
|
||||
```
|
||||
|
||||
**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="/operations">
|
||||
<results>
|
||||
<xsl:for-each select="op">
|
||||
<xsl:variable name="fn" select="
|
||||
if (@name = 'upper') then upper-case#1
|
||||
else lower-case#1"/>
|
||||
<result><xsl:value-of select="apply($fn, [string(@value)])"/></result>
|
||||
</xsl:for-each>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<result>HELLO</result>
|
||||
<result>world</result>
|
||||
</results>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `apply()` is defined in XPath 3.0 / XSLT 3.0. It is not available in XSLT 2.0 or earlier.
|
||||
- The function arity must exactly match the number of members in the array; a mismatch causes `err:FOAP0001`.
|
||||
- `apply()` is the complement of inline function items and partial function application.
|
||||
- Useful for implementing dispatch tables and strategy patterns in XSLT.
|
||||
|
||||
## See also
|
||||
|
||||
- [function-lookup()](../xpath-function-lookup)
|
||||
- [function-name()](../xpath-function-name)
|
||||
- [function-arity()](../xpath-function-arity)
|
||||
- [for-each()](../xpath-for-each)
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "array:append()"
|
||||
description: "Returns a new array with an additional member appended at the end."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:append(array, appendage)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:append()` returns a new array that is a copy of the input array with the `appendage` value added as a new final member. The appendage is added as a single member regardless of whether it is a sequence, making it distinct from `array:join()` which concatenates arrays.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The source array. |
|
||||
| `appendage` | item()* | Yes | The value to add as the new last member. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array with `array:size()` increased by 1.
|
||||
|
||||
## Examples
|
||||
|
||||
### Building an array by appending
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="base" select="['alpha', 'beta']"/>
|
||||
<xsl:variable name="plus1" select="array:append($base, 'gamma')"/>
|
||||
<xsl:variable name="plus2" select="array:append($plus1, 'delta')"/>
|
||||
<result size="{array:size($plus2)}">
|
||||
<xsl:for-each select="1 to array:size($plus2)">
|
||||
<item><xsl:value-of select="array:get($plus2, .)"/></item>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result size="4">
|
||||
<item>alpha</item>
|
||||
<item>beta</item>
|
||||
<item>gamma</item>
|
||||
<item>delta</item>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Accumulating results into an array with fold-left
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<scores>
|
||||
<score>85</score>
|
||||
<score>92</score>
|
||||
<score>78</score>
|
||||
<score>96</score>
|
||||
</scores>
|
||||
```
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/scores">
|
||||
<xsl:variable name="arr" select="fold-left(score, [],
|
||||
function($acc, $s) { array:append($acc, xs:integer($s)) }
|
||||
)"/>
|
||||
<stats>
|
||||
<count><xsl:value-of select="array:size($arr)"/></count>
|
||||
<max><xsl:value-of select="max(array:flatten($arr))"/></max>
|
||||
</stats>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<stats>
|
||||
<count>4</count>
|
||||
<max>96</max>
|
||||
</stats>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The `appendage` is added as a single member; if it is a sequence `(1,2)`, the new member is that two-item sequence, not two separate members.
|
||||
- To concatenate two arrays end-to-end, use `array:join(($arr1, $arr2))`.
|
||||
- Arrays are immutable; `array:append()` always returns a new array.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:join()](../xpath-array-join)
|
||||
- [array:insert-before()](../xpath-array-insert-before)
|
||||
- [array:remove()](../xpath-array-remove)
|
||||
- [array:size()](../xpath-array-size)
|
||||
- [xsl:array](../xsl-array)
|
||||
- [xsl:array-member](../xsl-array-member)
|
||||
@@ -0,0 +1,131 @@
|
||||
---
|
||||
title: "array:filter()"
|
||||
description: "Returns a new array containing only the members for which a predicate function returns true."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:filter(array, predicate)"
|
||||
tags: ["xslt", "reference", "xslt3", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:filter()` applies a predicate function to each member of the input array and returns a new array containing only the members for which the predicate returns `true`. The order of surviving members is preserved and the original array is not modified.
|
||||
|
||||
The predicate is an inline or named function with signature `function(item()*) as xs:boolean`. Each member of the array—whether it is a single item or a sequence—is passed to the predicate as a whole unit.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | `array(*)` | Yes | The source array whose members are tested. |
|
||||
| `predicate` | `function(item()*) as xs:boolean` | Yes | A function that returns true for members to keep. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array containing only the members for which the predicate returned `true`. The size may be zero if no members pass.
|
||||
|
||||
## Examples
|
||||
|
||||
### Filtering numbers greater than 5
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="numbers" select="[1, 7, 3, 9, 2, 6, 4, 8]"/>
|
||||
<xsl:variable name="above5" select="array:filter($numbers, function($n) { $n gt 5 })"/>
|
||||
<result>
|
||||
<input-size><xsl:value-of select="array:size($numbers)"/></input-size>
|
||||
<output-size><xsl:value-of select="array:size($above5)"/></output-size>
|
||||
<xsl:for-each select="1 to array:size($above5)">
|
||||
<value><xsl:value-of select="array:get($above5, .)"/></value>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<input-size>8</input-size>
|
||||
<output-size>4</output-size>
|
||||
<value>7</value>
|
||||
<value>9</value>
|
||||
<value>6</value>
|
||||
<value>8</value>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Filtering non-empty strings from an XML source
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tags>
|
||||
<tag>xslt</tag>
|
||||
<tag/>
|
||||
<tag>xpath</tag>
|
||||
<tag> </tag>
|
||||
<tag>saxon</tag>
|
||||
</tags>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/tags">
|
||||
<xsl:variable name="all" select="array:join(for $t in tag return [$t])"/>
|
||||
<xsl:variable name="filled" select="array:filter($all, function($t) { normalize-space($t) != '' })"/>
|
||||
<filtered count="{array:size($filled)}">
|
||||
<xsl:for-each select="1 to array:size($filled)">
|
||||
<tag><xsl:value-of select="array:get($filled, .)"/></tag>
|
||||
</xsl:for-each>
|
||||
</filtered>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<filtered count="3">
|
||||
<tag>xslt</tag>
|
||||
<tag>xpath</tag>
|
||||
<tag>saxon</tag>
|
||||
</filtered>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Each array member is passed as a whole unit to the predicate. A member that is itself a sequence is passed as that sequence, not as individual items.
|
||||
- `array:filter()` always returns a new array; the source array is unmodified.
|
||||
- To apply a transformation rather than a selection, use `array:for-each()`.
|
||||
- If no member satisfies the predicate, an empty array `[]` is returned.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:for-each()](../xpath-array-for-each)
|
||||
- [array:fold-left()](../xpath-array-fold-left)
|
||||
- [array:remove()](../xpath-array-remove)
|
||||
- [array:size()](../xpath-array-size)
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
title: "array:flatten()"
|
||||
description: "Recursively flattens nested arrays into a single flat sequence of atomic items and nodes."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:flatten(items)"
|
||||
tags: ["xslt", "reference", "xslt3", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:flatten()` takes a sequence of items that may contain arrays—including arrays nested inside arrays—and returns a flat sequence in which every array has been dissolved. Non-array items (strings, integers, nodes, maps, etc.) pass through unchanged; only array wrappers are removed.
|
||||
|
||||
The recursion is unbounded: a three-level-deep nesting such as `[[1, [2, 3]], [4]]` is fully flattened to `(1, 2, 3, 4)`. This makes `array:flatten()` useful when assembling arrays incrementally or when consuming data structures of unknown depth.
|
||||
|
||||
Note that the result is a **sequence**, not an array. Wrap it in `array:join()` if an array is required.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `items` | `item()*` | Yes | A sequence of items, which may include arrays at any depth of nesting. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — a flat sequence with all array wrappers removed. Maps are not unwrapped; only arrays are affected.
|
||||
|
||||
## Examples
|
||||
|
||||
### Flattening nested integer arrays
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="nested" select="[[1, 2], [3, [4, 5]], [6]]"/>
|
||||
<xsl:variable name="flat" select="array:flatten($nested)"/>
|
||||
<result>
|
||||
<flat><xsl:value-of select="$flat" separator=", "/></flat>
|
||||
<sum><xsl:value-of select="sum($flat)"/></sum>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<flat>1, 2, 3, 4, 5, 6</flat>
|
||||
<sum>21</sum>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Normalising a heterogeneous collection before processing
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<catalog>
|
||||
<group id="A">
|
||||
<item>alpha</item>
|
||||
<item>beta</item>
|
||||
</group>
|
||||
<group id="B">
|
||||
<item>gamma</item>
|
||||
</group>
|
||||
</catalog>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/catalog">
|
||||
<!-- Build one sub-array per group, then wrap them all -->
|
||||
<xsl:variable name="groups"
|
||||
select="array:join(for $g in group return [array:join(for $i in $g/item return [$i])])"/>
|
||||
<!-- Flatten the two-level structure into a single sequence -->
|
||||
<xsl:variable name="all" select="array:flatten($groups)"/>
|
||||
<items count="{count($all)}">
|
||||
<xsl:for-each select="$all">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</items>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<items count="3">
|
||||
<item>alpha</item>
|
||||
<item>beta</item>
|
||||
<item>gamma</item>
|
||||
</items>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Only arrays are unwrapped. Maps, even though they are also XDM structured types, are left intact.
|
||||
- The function accepts a plain sequence as its argument, not only an array. Items in the sequence that are not arrays pass through unchanged.
|
||||
- Members that are sequences (e.g. a member holding `(1, 2)`) remain as sequences inside the result because they are not themselves arrays.
|
||||
- To convert the resulting sequence back into an array, use `array:join()` with individual wrapping: `array:join(for $x in array:flatten($arr) return [$x])`.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:join()](../xpath-array-join)
|
||||
- [array:for-each()](../xpath-array-for-each)
|
||||
- [array:fold-left()](../xpath-array-fold-left)
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
title: "array:fold-left()"
|
||||
description: "Accumulates a result by applying a function to each array member from left to right, starting with a seed value."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:fold-left(array, zero, function)"
|
||||
tags: ["xslt", "reference", "xslt3", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:fold-left()` processes an array from its first member to its last, threading an accumulator through each step. For each member, the supplied function is called with the current accumulator value and the current member; its return value becomes the accumulator for the next step. After all members have been processed, the final accumulator value is returned.
|
||||
|
||||
When the array is empty, the `zero` (seed) value is returned unchanged without calling the function. This mirrors the mathematical notion of a left fold and is equivalent to the XPath 3.0 `fold-left()` function applied to sequences.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | `array(*)` | Yes | The array to fold. |
|
||||
| `zero` | `item()*` | Yes | The initial accumulator value, returned as-is when the array is empty. |
|
||||
| `function` | `function(item()*, item()*) as item()*` | Yes | A function taking `(accumulator, member)` and returning the new accumulator. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the final accumulated result after processing all members.
|
||||
|
||||
## Examples
|
||||
|
||||
### Summing an array of numbers
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="values" select="[10, 3, 7, 4, 6]"/>
|
||||
<xsl:variable name="sum"
|
||||
select="array:fold-left($values, 0, function($acc, $v) { $acc + $v })"/>
|
||||
<xsl:variable name="max"
|
||||
select="array:fold-left($values, array:get($values,1),
|
||||
function($acc, $v) { if ($v gt $acc) then $v else $acc })"/>
|
||||
<result>
|
||||
<sum><xsl:value-of select="$sum"/></sum>
|
||||
<max><xsl:value-of select="$max"/></max>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<sum>30</sum>
|
||||
<max>10</max>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Building a CSV line from an array of strings
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<record>
|
||||
<field>Alice</field>
|
||||
<field>Engineering</field>
|
||||
<field>London</field>
|
||||
</record>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/record">
|
||||
<xsl:variable name="fields"
|
||||
select="array:join(for $f in field return [string($f)])"/>
|
||||
<xsl:variable name="csv"
|
||||
select="array:fold-left(
|
||||
$fields,
|
||||
'',
|
||||
function($acc, $v) {
|
||||
if ($acc = '') then $v else concat($acc, ',', $v)
|
||||
}
|
||||
)"/>
|
||||
<xsl:value-of select="$csv"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Alice,Engineering,London
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:fold-left()` and `array:fold-right()` differ in the direction of traversal, which matters for non-commutative operations such as string concatenation or subtraction.
|
||||
- The zero value type must be compatible with the accumulator type expected by the function; Saxon enforces type consistency at runtime.
|
||||
- For very large arrays, folding is generally more efficient than recursive template calls because it avoids XSL overhead.
|
||||
- The XPath 3.0 `fold-left()` function (without the `array:` prefix) performs the same operation over sequences rather than arrays.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:fold-right()](../xpath-array-fold-right)
|
||||
- [array:for-each()](../xpath-array-for-each)
|
||||
- [array:filter()](../xpath-array-filter)
|
||||
- [array:size()](../xpath-array-size)
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
title: "array:fold-right()"
|
||||
description: "Accumulates a result by applying a function to each array member from right to left, starting with a seed value."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:fold-right(array, zero, function)"
|
||||
tags: ["xslt", "reference", "xslt3", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:fold-right()` traverses an array from its last member to its first, threading an accumulator through each step. For each member the supplied function is called with the current member and the current accumulator; its return value becomes the accumulator for the next (earlier) member. The final accumulator value after processing the first member is returned.
|
||||
|
||||
When the array is empty the `zero` seed is returned unchanged. The key distinction from `array:fold-left()` is the traversal direction and the argument order to the function: the member comes first, then the accumulator. This matters for operations that are not commutative, such as building a prefix string or constructing a right-associated structure.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | `array(*)` | Yes | The array to fold. |
|
||||
| `zero` | `item()*` | Yes | The initial accumulator value, returned as-is when the array is empty. |
|
||||
| `function` | `function(item()*, item()*) as item()*` | Yes | A function taking `(member, accumulator)` and returning the new accumulator. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the final accumulated result after processing all members from right to left.
|
||||
|
||||
## Examples
|
||||
|
||||
### Concatenating strings in reverse accumulation order
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="words" select="['one', 'two', 'three', 'four']"/>
|
||||
|
||||
<!-- fold-left: processes left to right, acc comes first -->
|
||||
<xsl:variable name="left-result"
|
||||
select="array:fold-left($words, '',
|
||||
function($acc, $v) { if ($acc='') then $v else concat($acc, ' > ', $v) })"/>
|
||||
|
||||
<!-- fold-right: processes right to left, member comes first -->
|
||||
<xsl:variable name="right-result"
|
||||
select="array:fold-right($words, '',
|
||||
function($v, $acc) { if ($acc='') then $v else concat($v, ' > ', $acc) })"/>
|
||||
|
||||
<result>
|
||||
<fold-left><xsl:value-of select="$left-result"/></fold-left>
|
||||
<fold-right><xsl:value-of select="$right-result"/></fold-right>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<fold-left>one > two > three > four</fold-left>
|
||||
<fold-right>one > two > three > four</fold-right>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Building a nested XML structure from right to left
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<path>
|
||||
<step>root</step>
|
||||
<step>section</step>
|
||||
<step>paragraph</step>
|
||||
</path>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/path">
|
||||
<xsl:variable name="steps"
|
||||
select="array:join(for $s in step return [string($s)])"/>
|
||||
<!-- Build breadcrumb from right: innermost processed first -->
|
||||
<xsl:variable name="breadcrumb"
|
||||
select="array:fold-right($steps, 'END',
|
||||
function($step, $acc) { concat($step, ' / ', $acc) })"/>
|
||||
<breadcrumb><xsl:value-of select="$breadcrumb"/></breadcrumb>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<breadcrumb>root / section / paragraph / END</breadcrumb>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The function signature for `array:fold-right()` is `function(member, accumulator)`, while `array:fold-left()` uses `function(accumulator, member)`. Confusing the argument order is a common mistake.
|
||||
- For commutative operations (addition, min, max) the fold direction produces the same result; for string concatenation and list building the direction matters.
|
||||
- Like all array functions, the operation returns a new value; no existing array is modified.
|
||||
- The XPath 3.0 sequence function `fold-right()` (without `array:` prefix) is the equivalent for ordinary sequences.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:fold-left()](../xpath-array-fold-left)
|
||||
- [array:for-each()](../xpath-array-for-each)
|
||||
- [array:filter()](../xpath-array-filter)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "array:for-each-pair()"
|
||||
description: "Returns a new array by applying the function to corresponding members of two arrays of the same size."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:for-each-pair(array1, array2, function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:for-each-pair()` applies a two-argument function to corresponding members of two arrays and returns a new array of the results. The function is called with the member from the first array and the member from the second array at each position. The two input arrays must have the same size; if they differ, a dynamic error is raised.
|
||||
|
||||
This function is the array analogue of the `for-each-pair()` higher-order function for sequences. It enables pairwise operations — such as computing differences, combining data from parallel arrays, or zipping two arrays together.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array1` | array(*) | Yes | The first input array. |
|
||||
| `array2` | array(*) | Yes | The second input array, must be the same size as array1. |
|
||||
| `function` | function(item()*, item()*) as item()* | Yes | A two-argument function applied to corresponding members. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array of the same size, where each member is the result of applying the function to the corresponding pair of members.
|
||||
|
||||
## Examples
|
||||
|
||||
### Adding corresponding elements
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="a" select="[1, 2, 3]"/>
|
||||
<xsl:variable name="b" select="[10, 20, 30]"/>
|
||||
<xsl:variable name="sums" select="array:for-each-pair($a, $b, function($x, $y) { $x + $y })"/>
|
||||
<sums>
|
||||
<xsl:for-each select="1 to array:size($sums)">
|
||||
<sum><xsl:value-of select="array:get($sums, .)"/></sum>
|
||||
</xsl:for-each>
|
||||
</sums>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<sums>
|
||||
<sum>11</sum>
|
||||
<sum>22</sum>
|
||||
<sum>33</sum>
|
||||
</sums>
|
||||
```
|
||||
|
||||
### Zipping names with scores
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<xsl:variable name="names" select="['Alice', 'Bob', 'Carol']"/>
|
||||
<xsl:variable name="scores" select="[95, 82, 91]"/>
|
||||
<xsl:variable name="zipped" select="array:for-each-pair($names, $scores,
|
||||
function($name, $score) { concat($name, ':', $score) })"/>
|
||||
<results>
|
||||
<xsl:for-each select="1 to array:size($zipped)">
|
||||
<entry><xsl:value-of select="array:get($zipped, .)"/></entry>
|
||||
</xsl:for-each>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<entry>Alice:95</entry>
|
||||
<entry>Bob:82</entry>
|
||||
<entry>Carol:91</entry>
|
||||
</results>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Both arrays must have the same number of members. If the sizes differ, a dynamic error is raised.
|
||||
- Each member is passed to the function as a sequence — a single-item member is a sequence of length one.
|
||||
- The result array has the same size as the inputs.
|
||||
- To process a single array with a two-argument function that also tracks the index, combine `array:for-each-pair()` with a position array created via `array:join(for $i in 1 to array:size($a) return [$i])`.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:for-each()](../xpath-array-for-each)
|
||||
- [array:filter()](../xpath-array-filter)
|
||||
- [array:fold-left()](../xpath-array-fold-left)
|
||||
- [array:flatten()](../xpath-array-flatten)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "array:for-each()"
|
||||
description: "Returns a new array where each member is the result of applying the function to the corresponding member of the input array."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:for-each(array, function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:for-each()` applies a function to each member of an array and returns a new array of the same size, where each member is the result of the function applied to the corresponding input member. The original array is not modified.
|
||||
|
||||
The function argument takes a single parameter: the current array member, which is a sequence. The function may return any XDM value — a single item, a sequence, or even an empty sequence — and the result becomes the corresponding member of the output array.
|
||||
|
||||
`array:for-each()` is the array equivalent of the sequence-level `for-each()` higher-order function, but it preserves array structure rather than flattening to a sequence.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The input array. |
|
||||
| `function` | function(item()*) as item()* | Yes | A function applied to each member. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array of the same size as the input, with each member replaced by the function result.
|
||||
|
||||
## Examples
|
||||
|
||||
### Squaring each element
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="nums" select="[1, 2, 3, 4, 5]"/>
|
||||
<xsl:variable name="squared" select="array:for-each($nums, function($n) { $n * $n })"/>
|
||||
<squares>
|
||||
<xsl:for-each select="1 to array:size($squared)">
|
||||
<val><xsl:value-of select="array:get($squared, .)"/></val>
|
||||
</xsl:for-each>
|
||||
</squares>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<squares>
|
||||
<val>1</val>
|
||||
<val>4</val>
|
||||
<val>9</val>
|
||||
<val>16</val>
|
||||
<val>25</val>
|
||||
</squares>
|
||||
```
|
||||
|
||||
### Uppercasing string members
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<xsl:variable name="words" select="['alpha', 'beta', 'gamma']"/>
|
||||
<xsl:variable name="upper" select="array:for-each($words, upper-case#1)"/>
|
||||
<words>
|
||||
<xsl:for-each select="1 to array:size($upper)">
|
||||
<word><xsl:value-of select="array:get($upper, .)"/></word>
|
||||
</xsl:for-each>
|
||||
</words>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<words>
|
||||
<word>ALPHA</word>
|
||||
<word>BETA</word>
|
||||
<word>GAMMA</word>
|
||||
</words>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:for-each()` always produces a new array of the same size as the input; it cannot drop or add members. Use `array:filter()` to remove members.
|
||||
- Named functions can be referenced using the function-reference syntax (`name#arity`) as shown in the second example.
|
||||
- Unlike `array:fold-left()`, `array:for-each()` does not accumulate state across members; each call is independent.
|
||||
- An empty array produces an empty array.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:filter()](../xpath-array-filter)
|
||||
- [array:fold-left()](../xpath-array-fold-left)
|
||||
- [array:for-each-pair()](../xpath-array-for-each-pair)
|
||||
- [array:flatten()](../xpath-array-flatten)
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: "array:get()"
|
||||
description: "Returns the member of an array at a specified 1-based position."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:get(array, position)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:get()` retrieves the member at the given 1-based integer position in an array. If the position is less than 1 or greater than the array size, error `err:FOAY0001` is raised. An alternative shorthand is `$array($position)` using function-call syntax.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The array to access. |
|
||||
| `position` | xs:integer | Yes | The 1-based position of the member to retrieve. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the member at the given position (may be a sequence if the member is a sequence).
|
||||
|
||||
## Examples
|
||||
|
||||
### Accessing array elements by position
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="colors" select="['red', 'green', 'blue', 'yellow']"/>
|
||||
<result>
|
||||
<!-- Both syntaxes are equivalent -->
|
||||
<first><xsl:value-of select="array:get($colors, 1)"/></first>
|
||||
<third><xsl:value-of select="$colors(3)"/></third>
|
||||
<last><xsl:value-of select="array:get($colors, array:size($colors))"/></last>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<first>red</first>
|
||||
<third>blue</third>
|
||||
<last>yellow</last>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Iterating with positional access
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="matrix" select="[[1,2,3],[4,5,6],[7,8,9]]"/>
|
||||
<matrix>
|
||||
<xsl:for-each select="1 to array:size($matrix)">
|
||||
<xsl:variable name="row-idx" select="."/>
|
||||
<row n="{$row-idx}">
|
||||
<xsl:variable name="row" select="array:get($matrix, $row-idx)"/>
|
||||
<xsl:for-each select="1 to array:size($row)">
|
||||
<cell><xsl:value-of select="array:get($row, .)"/></cell>
|
||||
</xsl:for-each>
|
||||
</row>
|
||||
</xsl:for-each>
|
||||
</matrix>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<matrix>
|
||||
<row n="1"><cell>1</cell><cell>2</cell><cell>3</cell></row>
|
||||
<row n="2"><cell>4</cell><cell>5</cell><cell>6</cell></row>
|
||||
<row n="3"><cell>7</cell><cell>8</cell><cell>9</cell></row>
|
||||
</matrix>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Positions are 1-based (not 0-based), consistent with XPath sequence indexing.
|
||||
- Out-of-bounds access raises `err:FOAY0001`; use `array:size()` to guard.
|
||||
- The shorthand `$array($pos)` is syntactic sugar for `array:get($array, $pos)`.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:size()](../xpath-array-size)
|
||||
- [array:head()](../xpath-array-head)
|
||||
- [array:put()](../xpath-array-put)
|
||||
- [array:subarray()](../xpath-array-subarray)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: "array:head()"
|
||||
description: "Returns the first member of an array; raises an error if the array is empty."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:head(array)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:head()` returns the value of the first member of an array. If the array is empty, error `err:FOAY0001` is raised. Together with `array:tail()`, it supports recursive pattern-matching style processing over arrays.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The array whose first member is to be returned. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the first member (which may itself be a sequence).
|
||||
|
||||
## Examples
|
||||
|
||||
### Accessing the first element safely
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="items" select="['first', 'second', 'third']"/>
|
||||
<result>
|
||||
<xsl:if test="array:size($items) gt 0">
|
||||
<head><xsl:value-of select="array:head($items)"/></head>
|
||||
</xsl:if>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<head>first</head>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Recursive processing with head and tail
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
|
||||
xmlns:f="http://example.com/fn">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:function name="f:sum-array" as="xs:integer">
|
||||
<xsl:param name="arr" as="array(xs:integer)"/>
|
||||
<xsl:sequence select="
|
||||
if (array:size($arr) = 0) then 0
|
||||
else array:head($arr) + f:sum-array(array:tail($arr))
|
||||
"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/">
|
||||
<result>
|
||||
<sum><xsl:value-of select="f:sum-array([10, 20, 30, 40])"/></sum>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<sum>100</sum>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Equivalent to `array:get($array, 1)`.
|
||||
- Raises `err:FOAY0001` on an empty array; guard with `array:size($arr) gt 0`.
|
||||
- Pair with `array:tail()` for list-processing patterns.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:tail()](../xpath-array-tail)
|
||||
- [array:get()](../xpath-array-get)
|
||||
- [array:size()](../xpath-array-size)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: "array:insert-before()"
|
||||
description: "Returns a new array with the given members inserted before the specified 1-based position."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:insert-before(array, position, members)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:insert-before()` returns a new array formed by inserting one or more new members into the input array just before the specified position. The `position` argument is 1-based. Inserting before position 1 prepends to the array; inserting before `array:size($array) + 1` appends to the array.
|
||||
|
||||
The `members` argument is treated as a sequence of new array members to insert, each becoming a separate member of the result array. This means the result array's size is `array:size(array) + count(members-sequence)`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The source array. |
|
||||
| `position` | xs:integer | Yes | The 1-based position before which to insert. |
|
||||
| `members` | item()* | Yes | The sequence of new members to insert. Each item in the sequence becomes a separate array member. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array with the inserted members, larger than the original.
|
||||
|
||||
## Examples
|
||||
|
||||
### Inserting at the beginning
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="a" select="['B', 'C', 'D']"/>
|
||||
<xsl:variable name="result" select="array:insert-before($a, 1, 'A')"/>
|
||||
<xsl:value-of select="array:flatten($result)" separator=" "/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
A B C D
|
||||
```
|
||||
|
||||
### Inserting in the middle
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<xsl:variable name="a" select="[1, 2, 5, 6]"/>
|
||||
<!-- Insert 3 and 4 before position 3 -->
|
||||
<xsl:variable name="result" select="array:insert-before($a, 3, (3, 4))"/>
|
||||
<array>
|
||||
<xsl:for-each select="1 to array:size($result)">
|
||||
<item><xsl:value-of select="array:get($result, .)"/></item>
|
||||
</xsl:for-each>
|
||||
</array>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<array>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
</array>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Inserting before position `array:size($array) + 1` is equivalent to appending; use `array:append()` for clarity.
|
||||
- The `members` argument is a sequence; each item in the sequence becomes a separate array member. To insert a single member that is itself a sequence, wrap it in an array and use `array:join()`.
|
||||
- Positions outside the range 1 to `size + 1` raise a dynamic error.
|
||||
- The source array is not modified; `array:insert-before()` always returns a new array.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:remove()](../xpath-array-remove)
|
||||
- [array:append()](../xpath-array-append)
|
||||
- [array:flatten()](../xpath-array-flatten)
|
||||
- [array:size()](../xpath-array-size)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: "array:join()"
|
||||
description: "Concatenates a sequence of arrays into a single array by combining all their members."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:join(arrays)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:join()` takes a sequence of arrays and returns a single array whose members are all the members of the input arrays concatenated in order. An empty sequence of arrays returns an empty array. This is distinct from `array:append()` which adds a single new member.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `arrays` | array(*)* | Yes | A sequence of arrays to concatenate. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array containing all members of all input arrays in order.
|
||||
|
||||
## Examples
|
||||
|
||||
### Joining two arrays
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="arr1" select="['a', 'b', 'c']"/>
|
||||
<xsl:variable name="arr2" select="['d', 'e']"/>
|
||||
<xsl:variable name="arr3" select="['f']"/>
|
||||
<xsl:variable name="joined" select="array:join(($arr1, $arr2, $arr3))"/>
|
||||
<result size="{array:size($joined)}">
|
||||
<xsl:for-each select="1 to array:size($joined)">
|
||||
<item><xsl:value-of select="array:get($joined, .)"/></item>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result size="6">
|
||||
<item>a</item>
|
||||
<item>b</item>
|
||||
<item>c</item>
|
||||
<item>d</item>
|
||||
<item>e</item>
|
||||
<item>f</item>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Building an array from chunked XML data
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<groups>
|
||||
<group id="A"><val>1</val><val>2</val></group>
|
||||
<group id="B"><val>3</val><val>4</val></group>
|
||||
</groups>
|
||||
```
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/groups">
|
||||
<xsl:variable name="arrays" select="
|
||||
for $g in group return
|
||||
fold-left($g/val, [],
|
||||
function($acc, $v) { array:append($acc, xs:integer($v)) }
|
||||
)"/>
|
||||
<xsl:variable name="all" select="array:join($arrays)"/>
|
||||
<all total="{sum(array:flatten($all))}">
|
||||
<xsl:for-each select="1 to array:size($all)">
|
||||
<n><xsl:value-of select="array:get($all, .)"/></n>
|
||||
</xsl:for-each>
|
||||
</all>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<all total="10">
|
||||
<n>1</n><n>2</n><n>3</n><n>4</n>
|
||||
</all>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:join(())` returns an empty array `[]`.
|
||||
- Unlike `array:append()`, which adds one item as a single member, `array:join()` merges the members of each array.
|
||||
- The result length equals the sum of the sizes of all input arrays.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:append()](../xpath-array-append)
|
||||
- [array:subarray()](../xpath-array-subarray)
|
||||
- [array:size()](../xpath-array-size)
|
||||
- [array:flatten()](../xpath-array-flatten)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "array:put()"
|
||||
description: "Returns a new array with the member at a given position replaced by a new value."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:put(array, position, value)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:put()` produces a new array identical to the input except that the member at the specified 1-based position is replaced with the new value. Arrays are immutable in XDM; the original array is not modified. Out-of-range positions raise `err:FOAY0001`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The source array. |
|
||||
| `position` | xs:integer | Yes | The 1-based position of the member to replace. |
|
||||
| `value` | item()* | Yes | The new value for that position. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array with the member at `position` replaced by `value`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Replacing a member in an array
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="original" select="['a', 'b', 'c', 'd']"/>
|
||||
<xsl:variable name="updated" select="array:put($original, 2, 'B')"/>
|
||||
<result>
|
||||
<xsl:for-each select="1 to array:size($updated)">
|
||||
<item><xsl:value-of select="array:get($updated, .)"/></item>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<item>a</item>
|
||||
<item>B</item>
|
||||
<item>c</item>
|
||||
<item>d</item>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Updating JSON-like array data
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<patch position="2" value="updated-value"/>
|
||||
```
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/patch">
|
||||
<xsl:variable name="data" select="['original-1', 'original-2', 'original-3']"/>
|
||||
<xsl:variable name="pos" select="xs:integer(@position)"/>
|
||||
<xsl:variable name="patched" select="array:put($data, $pos, string(@value))"/>
|
||||
<patched>
|
||||
<xsl:for-each select="1 to array:size($patched)">
|
||||
<item pos="{.}"><xsl:value-of select="array:get($patched, .)"/></item>
|
||||
</xsl:for-each>
|
||||
</patched>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<patched>
|
||||
<item pos="1">original-1</item>
|
||||
<item pos="2">updated-value</item>
|
||||
<item pos="3">original-3</item>
|
||||
</patched>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Array positions are 1-based. Position `0` or greater than `array:size()` raises `err:FOAY0001`.
|
||||
- The new value can be any XDM value, including a sequence (which becomes a single multi-item member).
|
||||
- Arrays are immutable; the result is always a new array.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:get()](../xpath-array-get)
|
||||
- [array:append()](../xpath-array-append)
|
||||
- [array:remove()](../xpath-array-remove)
|
||||
- [array:insert-before()](../xpath-array-insert-before)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: "array:remove()"
|
||||
description: "Returns a new array with the members at the specified 1-based positions removed."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:remove(array, positions)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:remove()` returns a new array with specified members omitted. The `positions` argument is a sequence of 1-based integers identifying the members to remove. Positions may be supplied in any order; duplicates are ignored. Members not listed in `positions` are retained in their original relative order.
|
||||
|
||||
If `positions` is the empty sequence, the function returns a copy of the input array unchanged. All specified positions must be valid (between 1 and `array:size(array)` inclusive); an out-of-range position raises a dynamic error.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The source array. |
|
||||
| `positions` | xs:integer* | Yes | A sequence of 1-based positions to remove. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array with the specified members removed, preserving the relative order of remaining members.
|
||||
|
||||
## Examples
|
||||
|
||||
### Removing a single member
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="a" select="['A', 'B', 'C', 'D']"/>
|
||||
<xsl:variable name="result" select="array:remove($a, 2)"/>
|
||||
<xsl:value-of select="array:flatten($result)" separator=" "/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
A C D
|
||||
```
|
||||
|
||||
### Removing multiple members
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<xsl:variable name="a" select="[10, 20, 30, 40, 50]"/>
|
||||
<!-- Remove positions 1 and 3 -->
|
||||
<xsl:variable name="result" select="array:remove($a, (1, 3))"/>
|
||||
<remaining>
|
||||
<xsl:for-each select="1 to array:size($result)">
|
||||
<item><xsl:value-of select="array:get($result, .)"/></item>
|
||||
</xsl:for-each>
|
||||
</remaining>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<remaining>
|
||||
<item>20</item>
|
||||
<item>40</item>
|
||||
<item>50</item>
|
||||
</remaining>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:remove()` removes by position, not by value. To remove by value, combine `array:filter()` with a value comparison.
|
||||
- Positions are 1-based, consistent with all other array functions.
|
||||
- Duplicate positions in the `positions` sequence are silently ignored.
|
||||
- Removing all positions results in an empty array `[]`; removing no positions (`()`) returns a copy of the input.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:insert-before()](../xpath-array-insert-before)
|
||||
- [array:filter()](../xpath-array-filter)
|
||||
- [array:subarray()](../xpath-array-subarray)
|
||||
- [array:size()](../xpath-array-size)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: "array:reverse()"
|
||||
description: "Returns a new array with the members in reverse order."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:reverse(array)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:reverse()` returns a new array whose members are in the reverse order of the input array. The function is a convenience over manual head/tail recursion and operates on the array structure directly, preserving each member as-is (including members that are sequences).
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The array whose members are to be reversed. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array with members in reverse order; an empty array if the input is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Reversing a simple array
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="original" select="[10, 20, 30, 40, 50]"/>
|
||||
<xsl:variable name="reversed" select="array:reverse($original)"/>
|
||||
<result>
|
||||
<xsl:for-each select="1 to array:size($reversed)">
|
||||
<n><xsl:value-of select="array:get($reversed, .)"/></n>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<n>50</n>
|
||||
<n>40</n>
|
||||
<n>30</n>
|
||||
<n>20</n>
|
||||
<n>10</n>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Reversing a sorted array for descending order
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<scores>
|
||||
<s>88</s><s>42</s><s>95</s><s>67</s>
|
||||
</scores>
|
||||
```
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/scores">
|
||||
<xsl:variable name="nums" select="for $s in s return xs:integer($s)"/>
|
||||
<!-- sort ascending then reverse for descending -->
|
||||
<xsl:variable name="sorted-asc" select="
|
||||
fold-left(sort($nums), [],
|
||||
function($acc, $n) { array:append($acc, $n) }
|
||||
)"/>
|
||||
<xsl:variable name="sorted-desc" select="array:reverse($sorted-asc)"/>
|
||||
<ranked>
|
||||
<xsl:for-each select="1 to array:size($sorted-desc)">
|
||||
<rank pos="{.}"><xsl:value-of select="array:get($sorted-desc, .)"/></rank>
|
||||
</xsl:for-each>
|
||||
</ranked>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<ranked>
|
||||
<rank pos="1">95</rank>
|
||||
<rank pos="2">88</rank>
|
||||
<rank pos="3">67</rank>
|
||||
<rank pos="4">42</rank>
|
||||
</ranked>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:reverse()` reverses member order only; individual members (including multi-item sequence members) are not affected internally.
|
||||
- An empty array returns an empty array without error.
|
||||
- For sequence reversal (not arrays), use `reverse()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:sort()](../xpath-array-sort)
|
||||
- [array:subarray()](../xpath-array-subarray)
|
||||
- [array:head()](../xpath-array-head)
|
||||
- [array:tail()](../xpath-array-tail)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: "array:size()"
|
||||
description: "Returns the number of members in an array."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:size(array)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:size()` returns the count of members in an array as an `xs:integer`. An empty array returns `0`. Unlike `count()` which operates on sequences, `array:size()` counts top-level members — each member may itself be a sequence or nested array.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The array whose member count is to be returned. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer` — the number of top-level members; `0` for an empty array.
|
||||
|
||||
## Examples
|
||||
|
||||
### Checking array size before access
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="items" select="['red', 'green', 'blue']"/>
|
||||
<result>
|
||||
<size><xsl:value-of select="array:size($items)"/></size>
|
||||
<empty><xsl:value-of select="array:size([])"/></empty>
|
||||
<safe>
|
||||
<xsl:if test="array:size($items) gt 0">
|
||||
<xsl:value-of select="array:head($items)"/>
|
||||
</xsl:if>
|
||||
</safe>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<size>3</size>
|
||||
<empty>0</empty>
|
||||
<safe>red</safe>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Comparing sequence count vs array size
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<!-- Each member is a sequence of 2 items, so array has 3 members -->
|
||||
<xsl:variable name="pairs" select="[('a',1), ('b',2), ('c',3)]"/>
|
||||
<result>
|
||||
<!-- array:size counts members (3), not total items (6) -->
|
||||
<array-size><xsl:value-of select="array:size($pairs)"/></array-size>
|
||||
<!-- array:flatten then count gives total items -->
|
||||
<flat-count><xsl:value-of select="count(array:flatten($pairs))"/></flat-count>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<array-size>3</array-size>
|
||||
<flat-count>6</flat-count>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:size()` counts top-level members; use `count(array:flatten($arr))` to count all atomic items recursively.
|
||||
- An array member that is an empty sequence still counts as one member.
|
||||
- Equivalent to `count(1 to array:size($arr))` but far more efficient.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:get()](../xpath-array-get)
|
||||
- [array:head()](../xpath-array-head)
|
||||
- [array:tail()](../xpath-array-tail)
|
||||
- [array:flatten()](../xpath-array-flatten)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: "array:sort()"
|
||||
description: "Returns a new array with members sorted using an optional collation and key function."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:sort(array, collation?, key-function?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:sort()` returns a new array whose members are in ascending order, determined by the sort key and collation. When no key function is supplied, members are compared directly using the default collation for strings or natural ordering for numbers and other atomic types. When a key function is supplied, it is applied to each member to derive the sort key; members are then sorted by their keys.
|
||||
|
||||
This function is the array equivalent of `sort()` for sequences or `xsl:sort` in templates. It does not modify the input array; it always returns a new one.
|
||||
|
||||
The `collation` argument controls string comparison. The `key-function` takes a single argument (the array member, which is a sequence) and returns an atomic value to use as the sort key.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The input array to sort. |
|
||||
| `collation` | xs:string? | No | URI of the collation to use for string comparison. Empty sequence uses the default. |
|
||||
| `key-function` | function(item()*) as xs:anyAtomicType* | No | A function that extracts the sort key from each member. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array with the same members in sorted order.
|
||||
|
||||
## Examples
|
||||
|
||||
### Sorting numbers in ascending order
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="nums" select="[5, 2, 8, 1, 9, 3]"/>
|
||||
<xsl:variable name="sorted" select="array:sort($nums)"/>
|
||||
<xsl:value-of select="array:flatten($sorted)" separator=" "/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
1 2 3 5 8 9
|
||||
```
|
||||
|
||||
### Sorting records by a key field
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<xsl:variable name="people" select="[
|
||||
map{'name': 'Charlie', 'age': 35},
|
||||
map{'name': 'Alice', 'age': 28},
|
||||
map{'name': 'Bob', 'age': 42}
|
||||
]"/>
|
||||
<xsl:variable name="by-name" select="array:sort($people, (), function($p) { map:get($p, 'name') })"/>
|
||||
<sorted>
|
||||
<xsl:for-each select="1 to array:size($by-name)">
|
||||
<xsl:variable name="p" select="array:get($by-name, .)"/>
|
||||
<person name="{map:get($p, 'name')}" age="{map:get($p, 'age')}"/>
|
||||
</xsl:for-each>
|
||||
</sorted>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<sorted>
|
||||
<person name="Alice" age="28"/>
|
||||
<person name="Bob" age="42"/>
|
||||
<person name="Charlie" age="35"/>
|
||||
</sorted>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:sort()` always sorts in ascending order. To sort in descending order, reverse the result with `array:reverse()`.
|
||||
- The collation argument may be `()` (empty sequence) to use the default collation, allowing the key function to be specified without supplying a collation.
|
||||
- Members that are sequences are compared by their atomized value; members that cannot be compared raise a type error.
|
||||
- An empty array returns an empty array.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:filter()](../xpath-array-filter)
|
||||
- [array:for-each()](../xpath-array-for-each)
|
||||
- [array:reverse()](../xpath-array-reverse)
|
||||
- [sort()](../xpath-sort)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "array:subarray()"
|
||||
description: "Returns a contiguous sub-array starting at a given position, with optional length."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:subarray(array, start, length?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:subarray()` extracts a portion of an array. The `start` position is 1-based. If `length` is omitted, all members from `start` to the end are returned. If `length` is 0, an empty array is returned. Out-of-range positions or negative lengths raise `err:FOAY0001`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The source array. |
|
||||
| `start` | xs:integer | Yes | The 1-based starting position. |
|
||||
| `length` | xs:integer? | No | Number of members to include. Defaults to all remaining members. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — the specified sub-array.
|
||||
|
||||
## Examples
|
||||
|
||||
### Slicing an array
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="data" select="['a','b','c','d','e','f']"/>
|
||||
<result>
|
||||
<!-- Items 2 through 4 -->
|
||||
<slice from="2" length="3">
|
||||
<xsl:value-of select="array:subarray($data, 2, 3)" separator=","/>
|
||||
</slice>
|
||||
<!-- Items from position 4 to end -->
|
||||
<tail from="4">
|
||||
<xsl:value-of select="array:subarray($data, 4)" separator=","/>
|
||||
</tail>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<slice from="2" length="3">b,c,d</slice>
|
||||
<tail from="4">d,e,f</tail>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Pagination with subarray
|
||||
|
||||
**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"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:param name="page" as="xs:integer" select="2"/>
|
||||
<xsl:param name="per-page" as="xs:integer" select="3"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="all" select="[1,2,3,4,5,6,7,8,9,10]"/>
|
||||
<xsl:variable name="start" select="($page - 1) * $per-page + 1"/>
|
||||
<xsl:variable name="len" select="min(($per-page, array:size($all) - $start + 1))"/>
|
||||
<xsl:variable name="page-data" select="array:subarray($all, $start, $len)"/>
|
||||
<page num="{$page}">
|
||||
<xsl:for-each select="1 to array:size($page-data)">
|
||||
<item><xsl:value-of select="array:get($page-data, .)"/></item>
|
||||
</xsl:for-each>
|
||||
</page>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (page=2, per-page=3):**
|
||||
```xml
|
||||
<page num="2">
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
</page>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `array:subarray($arr, 1)` returns a copy of the entire array.
|
||||
- `array:subarray($arr, 2)` is equivalent to `array:tail($arr)`.
|
||||
- `start` must be in the range `1` to `array:size($arr) + 1`; `length` must be non-negative.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:get()](../xpath-array-get)
|
||||
- [array:head()](../xpath-array-head)
|
||||
- [array:tail()](../xpath-array-tail)
|
||||
- [array:remove()](../xpath-array-remove)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: "array:tail()"
|
||||
description: "Returns a new array containing all members except the first; raises an error if the array is empty."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "array function"
|
||||
syntax: "array:tail(array)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`array:tail()` returns a new array that contains every member of the input array except the first one. If the array has one member, an empty array is returned. If the array is empty, error `err:FOAY0001` is raised. Used together with `array:head()` for recursive array processing.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `array` | array(*) | Yes | The source array. |
|
||||
|
||||
## Return value
|
||||
|
||||
`array(*)` — a new array with the first member removed; empty array if input had one member.
|
||||
|
||||
## Examples
|
||||
|
||||
### Popping the first element in a loop
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="original" select="['a', 'b', 'c', 'd']"/>
|
||||
<xsl:variable name="tail" select="array:tail($original)"/>
|
||||
<result>
|
||||
<head><xsl:value-of select="array:head($original)"/></head>
|
||||
<tail-size><xsl:value-of select="array:size($tail)"/></tail-size>
|
||||
<tail-first><xsl:value-of select="array:head($tail)"/></tail-first>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<head>a</head>
|
||||
<tail-size>3</tail-size>
|
||||
<tail-first>b</tail-first>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Recursive array reverse using head and tail
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
|
||||
xmlns:f="http://example.com/fn">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:function name="f:reverse-array" as="array(*)">
|
||||
<xsl:param name="arr" as="array(*)"/>
|
||||
<xsl:sequence select="
|
||||
if (array:size($arr) = 0) then []
|
||||
else array:append(f:reverse-array(array:tail($arr)), array:head($arr))
|
||||
"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="rev" select="f:reverse-array([1,2,3,4,5])"/>
|
||||
<result>
|
||||
<xsl:for-each select="1 to array:size($rev)">
|
||||
<n><xsl:value-of select="array:get($rev, .)"/></n>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<n>5</n><n>4</n><n>3</n><n>2</n><n>1</n>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Equivalent to `array:subarray($array, 2)`.
|
||||
- Raises `err:FOAY0001` for an empty array; guard with `array:size($arr) gt 0`.
|
||||
- For efficient list processing, prefer `array:fold-left()` or `array:for-each()` over manual head/tail recursion.
|
||||
|
||||
## See also
|
||||
|
||||
- [array:head()](../xpath-array-head)
|
||||
- [array:get()](../xpath-array-get)
|
||||
- [array:subarray()](../xpath-array-subarray)
|
||||
- [array:size()](../xpath-array-size)
|
||||
- [xsl:array](../xsl-array)
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: "available-environment-variables()"
|
||||
description: "Returns a sequence of strings naming the environment variables that are available to the processor."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "available-environment-variables()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`available-environment-variables()` returns a sequence of strings, each being the name of an environment variable that the processor is willing to expose. The order of the returned sequence is implementation-defined. If the processor exposes no environment variables, the function returns the empty sequence.
|
||||
|
||||
This function is used as a companion to `environment-variable()`: first call `available-environment-variables()` to discover what is exposed, then call `environment-variable()` with a specific name to retrieve its value. This pattern avoids relying on the empty-sequence return from `environment-variable()` as the sole indicator of absence.
|
||||
|
||||
The set of available variables may differ between development and production environments. Processors may restrict exposure for security or sandboxing reasons.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string*` — a sequence of environment variable names that the processor exposes, in implementation-defined order.
|
||||
|
||||
## Examples
|
||||
|
||||
### Listing available variables
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<env-vars>
|
||||
<xsl:for-each select="sort(available-environment-variables())">
|
||||
<var name="{.}"/>
|
||||
</xsl:for-each>
|
||||
</env-vars>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (varies by environment):**
|
||||
```xml
|
||||
<env-vars>
|
||||
<var name="HOME"/>
|
||||
<var name="PATH"/>
|
||||
<var name="USER"/>
|
||||
</env-vars>
|
||||
```
|
||||
|
||||
### Checking whether a specific variable is exposed
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:choose>
|
||||
<xsl:when test="'APP_MODE' = available-environment-variables()">
|
||||
Mode: <xsl:value-of select="environment-variable('APP_MODE')"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>APP_MODE not available</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
APP_MODE not available
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The result of `available-environment-variables()` may be an empty sequence even when the OS has environment variables set, if the processor has disabled access.
|
||||
- The function is particularly useful in test harnesses that need to adapt behavior based on the current environment without hard-coding variable names.
|
||||
- `available-environment-variables()` is a pure function: it has no side effects and returns the same result for repeated calls within a single transformation.
|
||||
- In Saxon, this function returns all OS-level environment variables by default. Use Saxon's `-feature` flag to restrict access if needed.
|
||||
|
||||
## See also
|
||||
|
||||
- [environment-variable()](../xpath-environment-variable)
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: "avg()"
|
||||
description: "Returns the arithmetic mean of a sequence of numeric values, or the empty sequence if the input is empty."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "numeric function"
|
||||
syntax: "avg(sequence)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`avg()` computes the arithmetic mean of all values in a sequence. All items in the sequence must be of a common numeric type (or castable to one). If the sequence is empty, the empty sequence is returned rather than an error.
|
||||
|
||||
Duration types (`xs:yearMonthDuration`, `xs:dayTimeDuration`) are also supported.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | xs:anyAtomicType* | Yes | A sequence of numeric or duration values to average. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyAtomicType?` — the arithmetic mean of the values, using the promoted common type of the sequence items. Returns the empty sequence when the input is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Average of element values
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<scores>
|
||||
<score>85</score>
|
||||
<score>92</score>
|
||||
<score>78</score>
|
||||
<score>95</score>
|
||||
</scores>
|
||||
```
|
||||
|
||||
**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="/scores">
|
||||
<result>
|
||||
<average><xsl:value-of select="avg(score/xs:integer(.))"/></average>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<average>87.5</average>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Average with grouped data
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sales>
|
||||
<sale region="north" amount="100"/>
|
||||
<sale region="south" amount="200"/>
|
||||
<sale region="north" amount="150"/>
|
||||
<sale region="south" amount="180"/>
|
||||
</sales>
|
||||
```
|
||||
|
||||
**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="/sales">
|
||||
<averages>
|
||||
<xsl:for-each-group select="sale" group-by="@region">
|
||||
<region name="{current-grouping-key()}">
|
||||
<avg><xsl:value-of select="avg(current-group()/xs:decimal(@amount))"/></avg>
|
||||
</region>
|
||||
</xsl:for-each-group>
|
||||
</averages>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<averages>
|
||||
<region name="north"><avg>125</avg></region>
|
||||
<region name="south"><avg>190</avg></region>
|
||||
</averages>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- All items in the sequence must be of a compatible numeric type. Mixing `xs:integer` and `xs:string` raises a type error.
|
||||
- `avg()` is not available in XSLT 1.0. Use `sum() div count()` as a 1.0 equivalent.
|
||||
- For an empty sequence, the function returns the empty sequence (not `NaN` or zero).
|
||||
|
||||
## See also
|
||||
|
||||
- [abs()](../xpath-abs)
|
||||
- [min()](../xpath-min)
|
||||
- [max()](../xpath-max)
|
||||
- [sum()](../xpath-sum)
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: "base-uri()"
|
||||
description: "Returns the base URI of a node as an xs:anyURI, combining the document's URI with any xml:base attributes in scope."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "base-uri(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`base-uri()` returns the base URI of a node. The base URI is determined by combining the document URI (from where the document was loaded) with any `xml:base` attributes present on ancestor elements. It follows the XML Base specification (RFC 3986 resolution).
|
||||
|
||||
When called without an argument, the context node is used. If the argument is the empty sequence, the empty sequence is returned. If no base URI can be determined, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node()? | No | The node whose base URI is requested. Defaults to the context node. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyURI?` — the base URI of the node, or the empty sequence if no base URI is available.
|
||||
|
||||
## Examples
|
||||
|
||||
### Report base URIs of elements with xml:base
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root xml:base="http://example.com/docs/">
|
||||
<chapter xml:base="chapter1/">
|
||||
<section>Introduction</section>
|
||||
</chapter>
|
||||
</root>
|
||||
```
|
||||
|
||||
**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="/root">
|
||||
<base-uris>
|
||||
<root-base><xsl:value-of select="base-uri(.)"/></root-base>
|
||||
<chapter-base><xsl:value-of select="base-uri(chapter)"/></chapter-base>
|
||||
<section-base><xsl:value-of select="base-uri(chapter/section)"/></section-base>
|
||||
</base-uris>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<base-uris>
|
||||
<root-base>http://example.com/docs/</root-base>
|
||||
<chapter-base>http://example.com/docs/chapter1/</chapter-base>
|
||||
<section-base>http://example.com/docs/chapter1/</section-base>
|
||||
</base-uris>
|
||||
```
|
||||
|
||||
### Use base-uri to resolve relative links
|
||||
|
||||
**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="/doc">
|
||||
<links>
|
||||
<xsl:for-each select="link">
|
||||
<resolved>
|
||||
<xsl:value-of select="resolve-uri(@href, base-uri(.))"/>
|
||||
</resolved>
|
||||
</xsl:for-each>
|
||||
</links>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- If the document was parsed from a string (without a known URI), `base-uri()` may return the empty sequence.
|
||||
- `base-uri()` is affected by `xml:base` attributes anywhere in the ancestor chain. The effective base URI is the result of resolving each `xml:base` relative to the one above.
|
||||
- To get the base URI of the stylesheet module itself, use `static-base-uri()`.
|
||||
- To get the URI of the root document node (ignoring `xml:base`), use `document-uri()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [document-uri()](../xpath-document-uri)
|
||||
- [static-base-uri()](../xpath-static-base-uri)
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "boolean()"
|
||||
description: "Converts any XPath value — node-set, string, number, or boolean — to a boolean according to XPath 1.0 rules."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "boolean function"
|
||||
syntax: "boolean(object)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`boolean()` converts its argument to a boolean value following the XPath 1.0 type-conversion rules. The result is always `true` or `false`.
|
||||
|
||||
The conversion rules depend on the type of the argument:
|
||||
|
||||
- **Node-set:** `true` if the node-set is non-empty, `false` otherwise.
|
||||
- **String:** `true` if the string has a length greater than zero, `false` for the empty string `""`.
|
||||
- **Number:** `true` if the number is not zero and not `NaN`, `false` for `0` and `NaN`.
|
||||
- **Boolean:** returned unchanged.
|
||||
|
||||
In practice, most XPath predicates and `xsl:if/@test` expressions perform an implicit boolean conversion, so an explicit call to `boolean()` is needed only when you want to convert a value to a boolean for output or further processing.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `object` | any | Yes | The value to convert. Accepts node-set, string, number, or boolean. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` or `false` according to the XPath 1.0 boolean conversion rules.
|
||||
|
||||
## Examples
|
||||
|
||||
### Convert a string to boolean
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config>
|
||||
<label>active</label>
|
||||
<empty></empty>
|
||||
</config>
|
||||
```
|
||||
|
||||
**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="/config">
|
||||
<results>
|
||||
<has-label><xsl:value-of select="boolean(label)"/></has-label>
|
||||
<has-empty><xsl:value-of select="boolean(empty)"/></has-empty>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<has-label>true</has-label>
|
||||
<has-empty>false</has-empty>
|
||||
</results>
|
||||
```
|
||||
|
||||
### Convert a number to boolean
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data>
|
||||
<count>5</count>
|
||||
<zero>0</zero>
|
||||
</data>
|
||||
```
|
||||
|
||||
**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="/data">
|
||||
<results>
|
||||
<count-bool><xsl:value-of select="boolean(number(count))"/></count-bool>
|
||||
<zero-bool><xsl:value-of select="boolean(number(zero))"/></zero-bool>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<count-bool>true</count-bool>
|
||||
<zero-bool>false</zero-bool>
|
||||
</results>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- An empty node-set, an empty string, the number `0`, and `NaN` all convert to `false`. Everything else converts to `true`.
|
||||
- Calling `boolean()` explicitly is uncommon inside `xsl:if/@test` because XPath already evaluates the test expression as a boolean. Use it when you need to output the literal string `"true"` or `"false"`.
|
||||
- `NaN` (produced by operations like `number('abc')`) converts to `false`, not an error.
|
||||
- In XSLT 2.0+ the `xs:boolean()` constructor and the `fn:boolean()` function behave similarly but operate on sequences; an empty sequence returns `false`.
|
||||
|
||||
## See also
|
||||
|
||||
- [not()](../xpath-not)
|
||||
- [true()](../xpath-true)
|
||||
- [false()](../xpath-false)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: "ceiling()"
|
||||
description: "Returns the smallest integer not less than the argument — equivalent to rounding a number up toward positive infinity."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "numeric function"
|
||||
syntax: "ceiling(number)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`ceiling()` returns the smallest integer that is greater than or equal to its argument. It rounds a number **up** toward positive infinity. For positive numbers with a fractional part this means adding enough to reach the next integer; for negative numbers it rounds toward zero.
|
||||
|
||||
The argument is first converted to a number using the same rules as `number()`. If the argument is already an integer, it is returned unchanged. Special values (`NaN`, `Infinity`, `-Infinity`) pass through unmodified.
|
||||
|
||||
`ceiling()` is the complement of `floor()`. It is commonly used to compute the total number of pages needed to display a set of items, to round monetary amounts up to the next whole unit, or to ensure allocated space is never less than required.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `number` | xs:double | Yes | The number to round up. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:double` — the smallest integer value greater than or equal to the argument.
|
||||
|
||||
## Examples
|
||||
|
||||
### Total pages needed for a list of items
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<catalog>
|
||||
<item>A</item>
|
||||
<item>B</item>
|
||||
<item>C</item>
|
||||
<item>D</item>
|
||||
<item>E</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:variable name="pageSize" select="2"/>
|
||||
|
||||
<xsl:template match="/catalog">
|
||||
<xsl:variable name="total" select="count(item)"/>
|
||||
<pagination>
|
||||
<total-items><xsl:value-of select="$total"/></total-items>
|
||||
<pages-needed><xsl:value-of select="ceiling($total div $pageSize)"/></pages-needed>
|
||||
</pagination>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<pagination>
|
||||
<total-items>5</total-items>
|
||||
<pages-needed>3</pages-needed>
|
||||
</pagination>
|
||||
```
|
||||
|
||||
### Ceiling of positive and negative numbers
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<values>
|
||||
<v>3.2</v>
|
||||
<v>-3.2</v>
|
||||
<v>4.0</v>
|
||||
</values>
|
||||
```
|
||||
|
||||
**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="/values">
|
||||
<results>
|
||||
<xsl:for-each select="v">
|
||||
<ceiling of="{.}"><xsl:value-of select="ceiling(.)"/></ceiling>
|
||||
</xsl:for-each>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<ceiling of="3.2">4</ceiling>
|
||||
<ceiling of="-3.2">-3</ceiling>
|
||||
<ceiling of="4.0">4</ceiling>
|
||||
</results>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `ceiling(-3.2)` returns `-3`, not `-4`. The direction is always toward positive infinity.
|
||||
- If the argument is `NaN`, `ceiling()` returns `NaN`.
|
||||
- If the argument is `Infinity` or `-Infinity`, the same infinity is returned unchanged.
|
||||
- Like `floor()`, the return type is `xs:double`, so serialisation may show a trailing `.0` on some processors.
|
||||
- When dividing integers, use `ceiling($a div $b)` rather than `ceiling($a) div $b`; the latter rounds the numerator first and can produce incorrect results.
|
||||
|
||||
## See also
|
||||
|
||||
- [floor()](../xpath-floor)
|
||||
- [round()](../xpath-round)
|
||||
- [number()](../xpath-number)
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: "codepoints-to-string()"
|
||||
description: "Constructs a string from a sequence of Unicode codepoint integers, enabling programmatic string assembly from character codes."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "codepoints-to-string(sequence)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`codepoints-to-string()` takes a sequence of integer Unicode codepoints and returns the string formed by the corresponding characters in that order. It is the inverse of `string-to-codepoints()`.
|
||||
|
||||
This function is useful when you need to:
|
||||
- Construct strings containing characters that are hard to type or embed in XML.
|
||||
- Build strings programmatically from computed character codes.
|
||||
- Round-trip through codepoint manipulation (e.g., ROT-13, Caesar cipher).
|
||||
|
||||
If the sequence is empty, the function returns an empty string. An error is raised if any integer in the sequence is not a valid XML character codepoint (e.g., codepoints in the surrogate range U+D800–U+DFFF).
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | xs:integer* | Yes | A sequence of Unicode codepoint integers. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the string formed by concatenating the characters for each codepoint in order.
|
||||
|
||||
## Examples
|
||||
|
||||
### Building a string from codepoints
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<results>
|
||||
<!-- Codepoints for 'Hello' -->
|
||||
<word><xsl:value-of select="codepoints-to-string((72, 101, 108, 108, 111))"/></word>
|
||||
<!-- Tab character (U+0009) -->
|
||||
<tab-char><xsl:value-of select="codepoints-to-string(9)"/></tab-char>
|
||||
<!-- Copyright sign (U+00A9) -->
|
||||
<copyright><xsl:value-of select="codepoints-to-string(169)"/></copyright>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<word>Hello</word>
|
||||
<tab-char> </tab-char>
|
||||
<copyright>©</copyright>
|
||||
</results>
|
||||
```
|
||||
|
||||
### Applying a simple character shift (Caesar cipher)
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<messages>
|
||||
<msg>Hello</msg>
|
||||
</messages>
|
||||
```
|
||||
|
||||
**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:function name="my:rot13" as="xs:string" xmlns:my="http://example.com/my">
|
||||
<xsl:param name="s" as="xs:string"/>
|
||||
<xsl:value-of select="codepoints-to-string(
|
||||
for $cp in string-to-codepoints($s) return
|
||||
if ($cp ge 65 and $cp le 90) then (($cp - 65 + 13) mod 26) + 65
|
||||
else if ($cp ge 97 and $cp le 122) then (($cp - 97 + 13) mod 26) + 97
|
||||
else $cp
|
||||
)"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/messages">
|
||||
<encoded>
|
||||
<xsl:for-each select="msg">
|
||||
<msg><xsl:value-of select="my:rot13(.)"/></msg>
|
||||
</xsl:for-each>
|
||||
</encoded>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<encoded>
|
||||
<msg>Uryyb</msg>
|
||||
</encoded>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Codepoints must be valid XML characters. Codepoints 0 (except in some contexts), and the range U+D800–U+DFFF (surrogates) are not valid and will cause a dynamic error.
|
||||
- The function accepts a single integer or a sequence of integers interchangeably.
|
||||
- Combining with `string-to-codepoints()` enables low-level string transformations without regular expressions.
|
||||
- Codepoint 32 is a space, 10 is a newline (` `), 9 is a tab (`	`).
|
||||
|
||||
## See also
|
||||
|
||||
- [string-to-codepoints()](../xpath-string-to-codepoints)
|
||||
- [normalize-unicode()](../xpath-normalize-unicode)
|
||||
- [compare()](../xpath-compare)
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: "collection()"
|
||||
description: "Returns a sequence of nodes from a named collection, enabling batch processing of multiple XML documents."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "collection(uri?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`collection()` returns a sequence of nodes from a **collection** identified by a URI. A collection is a processor-defined set of nodes — typically a set of XML documents. The most common use in Saxon is to pass a directory URI, which the processor expands to all XML files in that directory.
|
||||
|
||||
When called without an argument (or with the empty sequence), the **default collection** is returned. The default collection may be set programmatically via the processor's API.
|
||||
|
||||
The exact semantics of the URI are implementation-defined.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `uri` | xs:string? | No | URI identifying the collection. Omit or pass the empty sequence for the default collection. |
|
||||
|
||||
## Return value
|
||||
|
||||
`node()*` — a sequence of nodes from the collection, typically document nodes.
|
||||
|
||||
## Examples
|
||||
|
||||
### Process all XML files in a directory (Saxon)
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<catalog>
|
||||
<xsl:for-each select="collection('file:///data/books/?select=*.xml')">
|
||||
<book uri="{document-uri(.)}">
|
||||
<title><xsl:value-of select="*/title"/></title>
|
||||
</book>
|
||||
</xsl:for-each>
|
||||
</catalog>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example with two files):**
|
||||
```xml
|
||||
<catalog>
|
||||
<book uri="file:///data/books/book1.xml">
|
||||
<title>Learning XSLT</title>
|
||||
</book>
|
||||
<book uri="file:///data/books/book2.xml">
|
||||
<title>XPath in Practice</title>
|
||||
</book>
|
||||
</catalog>
|
||||
```
|
||||
|
||||
### Merge elements from all collected documents
|
||||
|
||||
**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="/">
|
||||
<merged>
|
||||
<xsl:for-each select="collection('file:///data/reports/?select=*.xml')/report/entry">
|
||||
<xsl:copy-of select="."/>
|
||||
</xsl:for-each>
|
||||
</merged>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The URI syntax for directory collections is Saxon-specific: `file:///path/?select=*.xml` selects XML files; `recurse=yes` enables recursive directory traversal.
|
||||
- Saxon also supports catalog-style collection documents (an XML file listing URIs).
|
||||
- The order of nodes in the returned sequence is implementation-defined.
|
||||
- For a sequence of URIs rather than document nodes, use `uri-collection()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [uri-collection()](../xpath-uri-collection)
|
||||
- [document-uri()](../xpath-document-uri)
|
||||
@@ -0,0 +1,130 @@
|
||||
---
|
||||
title: "compare()"
|
||||
description: "Compares two strings using a collation and returns -1, 0, or 1 indicating their relative order."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "compare(string1, string2, collation?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`compare()` performs a three-way comparison of two strings, returning:
|
||||
|
||||
- `-1` if `string1` sorts before `string2`
|
||||
- `0` if they are equal
|
||||
- `1` if `string1` sorts after `string2`
|
||||
|
||||
Without a `collation` argument, the default collation (Unicode codepoint order) is used. With a collation URI, language- and locale-sensitive ordering is applied — for example, treating accented and unaccented letters as equivalent, or following locale-specific alphabetical order.
|
||||
|
||||
This is the XPath 2.0 equivalent of the three-way comparison operators found in languages like Java (`compareTo`) or C (`strcmp`), and it is the correct function to use when you need ordered comparison rather than just equality.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string1` | xs:string? | Yes | The first string. |
|
||||
| `string2` | xs:string? | Yes | The second string. |
|
||||
| `collation` | xs:string | No | A collation URI. Defaults to the default collation (typically Unicode codepoint). |
|
||||
|
||||
If either argument is an empty sequence, the function returns an empty sequence.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer?` — `-1`, `0`, or `1`, or the empty sequence if either argument is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Sorting strings and finding the alphabetically first
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<words>
|
||||
<word>banana</word>
|
||||
<word>apple</word>
|
||||
<word>cherry</word>
|
||||
<word>date</word>
|
||||
</words>
|
||||
```
|
||||
|
||||
**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="/words">
|
||||
<!-- Find the alphabetically first word using compare() -->
|
||||
<xsl:variable name="first">
|
||||
<xsl:perform-sort select="word">
|
||||
<xsl:sort select="."/>
|
||||
</xsl:perform-sort>
|
||||
</xsl:variable>
|
||||
<first><xsl:value-of select="$first/word[1]"/></first>
|
||||
|
||||
<!-- Test compare() directly -->
|
||||
<comparison>
|
||||
<result><xsl:value-of select="compare('apple', 'banana')"/></result>
|
||||
<result><xsl:value-of select="compare('banana', 'apple')"/></result>
|
||||
<result><xsl:value-of select="compare('apple', 'apple')"/></result>
|
||||
</comparison>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<first>apple</first>
|
||||
<comparison>
|
||||
<result>-1</result>
|
||||
<result>1</result>
|
||||
<result>0</result>
|
||||
</comparison>
|
||||
```
|
||||
|
||||
### Custom sort using compare() in a 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:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:my="http://example.com/my">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<!-- Returns the lexicographically greater of two strings -->
|
||||
<xsl:function name="my:max-string" as="xs:string">
|
||||
<xsl:param name="a" as="xs:string"/>
|
||||
<xsl:param name="b" as="xs:string"/>
|
||||
<xsl:sequence select="if (compare($a, $b) ge 0) then $a else $b"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/">
|
||||
<result>
|
||||
<xsl:value-of select="my:max-string('pear', 'peach')"/>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>pear</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- For simple equality testing, use `=` or `eq`. `compare()` is most useful when you need the direction of the difference, not just whether strings are equal.
|
||||
- Codepoint collation compares characters by Unicode code number, which does not always match alphabetical order in all languages.
|
||||
- Saxon supports IETF BCP 47 language tags as collation URIs (e.g., `http://saxon.sf.net/collation?lang=fr` for French).
|
||||
- `compare($a, $b) = 0` is equivalent to `$a = $b` under the same collation.
|
||||
|
||||
## See also
|
||||
|
||||
- [upper-case()](../xpath-upper-case)
|
||||
- [lower-case()](../xpath-lower-case)
|
||||
- [codepoints-to-string()](../xpath-codepoints-to-string)
|
||||
- [deep-equal()](../xpath-deep-equal)
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: "copy-of()"
|
||||
description: "Returns a deep copy of all nodes in the sequence, detached from the original document."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "copy-of(sequence)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`copy-of()` returns a deep copy of each node in the sequence. The copies are new nodes that are not part of any existing document tree — they are detached roots. Modifications to the original nodes do not affect the copies, and the copies share no identity with their originals.
|
||||
|
||||
This function is the XPath 2.0 function counterpart to the `xsl:copy-of` instruction. It is especially useful inside XPath expressions where you need to pass a fresh copy of a subtree to a function, store it in a variable, or use it as a constructor argument.
|
||||
|
||||
Atomic values in the sequence are returned as-is; only node items are copied.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The nodes (and atomic values) to copy. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — deep copies of any node items in the sequence; atomic values returned unchanged.
|
||||
|
||||
## Examples
|
||||
|
||||
### Storing a copy in a variable
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<library>
|
||||
<book><title>XSLT 2.0</title><author>Kay</author></book>
|
||||
<book><title>XPath</title><author>Mangano</author></book>
|
||||
</library>
|
||||
```
|
||||
|
||||
**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="/library">
|
||||
<xsl:variable name="snapshot" select="copy-of(book)"/>
|
||||
<copies>
|
||||
<xsl:for-each select="$snapshot">
|
||||
<xsl:copy-of select="."/>
|
||||
</xsl:for-each>
|
||||
</copies>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<copies>
|
||||
<book><title>XSLT 2.0</title><author>Kay</author></book>
|
||||
<book><title>XPath</title><author>Mangano</author></book>
|
||||
</copies>
|
||||
```
|
||||
|
||||
### Passing a copy to a 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:f="urn:functions">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:function name="f:wrap">
|
||||
<xsl:param name="nodes" as="node()*"/>
|
||||
<wrapper>
|
||||
<xsl:copy-of select="$nodes"/>
|
||||
</wrapper>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/library">
|
||||
<xsl:copy-of select="f:wrap(copy-of(book[1]))"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<wrapper>
|
||||
<book><title>XSLT 2.0</title><author>Kay</author></book>
|
||||
</wrapper>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `copy-of()` creates parentless copies; the copies have no document-node parent and no sibling nodes.
|
||||
- The function copies all descendants, attributes, namespace nodes, and text content recursively.
|
||||
- It differs from `xsl:copy-of` (the instruction) in that it can be used inline in an XPath expression rather than as a standalone instruction.
|
||||
- In XSLT 3.0, `snapshot()` serves a similar purpose for streaming contexts where nodes may not be available after the streaming pass ends.
|
||||
|
||||
## See also
|
||||
|
||||
- [snapshot()](../xpath-snapshot)
|
||||
- [deep-equal()](../xpath-deep-equal)
|
||||
- [xsl:copy-of](../xsl-copy-of)
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: "current-dateTime()"
|
||||
description: "Returns the current date and time as an xs:dateTime value, fixed for the duration of the transformation."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "current-dateTime()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-dateTime()` returns the current date and time as a single `xs:dateTime` value, including the implicit timezone of the processor. The value is **fixed** for the entire transformation, so all calls within a single run return the same timestamp.
|
||||
|
||||
It is the most complete timestamp function in XPath 2.0, combining both the date information of `current-date()` and the time information of `current-time()`.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:dateTime` — the current date and time in ISO 8601 form `YYYY-MM-DDTHH:MM:SS.sss+HH:MM`. Stable for the lifetime of the transformation.
|
||||
|
||||
## Examples
|
||||
|
||||
### Add a full ISO timestamp to the root element
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<export>
|
||||
<record id="1">Alpha</record>
|
||||
<record id="2">Beta</record>
|
||||
</export>
|
||||
```
|
||||
|
||||
**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="/export">
|
||||
<export timestamp="{current-dateTime()}">
|
||||
<xsl:copy-of select="*"/>
|
||||
</export>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```xml
|
||||
<export timestamp="2026-04-18T14:32:07.123+01:00">
|
||||
<record id="1">Alpha</record>
|
||||
<record id="2">Beta</record>
|
||||
</export>
|
||||
```
|
||||
|
||||
### Format a human-readable timestamp
|
||||
|
||||
**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-dateTime(current-dateTime(), '[FNn] [D] [MNn] [Y] at [H01]:[m01]')"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```
|
||||
Saturday 18 April 2026 at 14:32
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Not available in XSLT 1.0.
|
||||
- All three functions — `current-date()`, `current-time()`, and `current-dateTime()` — return consistent values derived from the same instant.
|
||||
- Use `xs:date(current-dateTime())` to extract just the date portion, or `xs:time(current-dateTime())` for just the time.
|
||||
- Pair with `format-dateTime()` to produce locale-aware output.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-date()](../xpath-current-date)
|
||||
- [current-time()](../xpath-current-time)
|
||||
- [format-dateTime()](../xpath-format-date-time)
|
||||
- [format-date()](../xpath-format-date)
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: "current-date()"
|
||||
description: "Returns the current date as an xs:date value, stable for the duration of the transformation."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "current-date()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-date()` returns today's date as an `xs:date` value. The returned value includes the implicit timezone of the processor. Crucially, the value is **fixed** for the entire transformation: all calls within one transformation return the same date, ensuring consistency across the output.
|
||||
|
||||
This is the typed-value counterpart to calling `substring-before(string(current-dateTime()), 'T')` in XSLT 1.0.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:date` — the current date in the form `YYYY-MM-DD+HH:MM` (with timezone offset). The date is stable for the lifetime of the transformation.
|
||||
|
||||
## Examples
|
||||
|
||||
### Stamp a document with today's date
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<title>Annual Summary</title>
|
||||
</report>
|
||||
```
|
||||
|
||||
**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="/report">
|
||||
<report>
|
||||
<generated><xsl:value-of select="current-date()"/></generated>
|
||||
<xsl:copy-of select="*"/>
|
||||
</report>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```xml
|
||||
<report>
|
||||
<generated>2026-04-18+01:00</generated>
|
||||
<title>Annual Summary</title>
|
||||
</report>
|
||||
```
|
||||
|
||||
### Format today's date for display
|
||||
|
||||
**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(), '[FNn], [D] [MNn] [Y]')"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```
|
||||
Saturday, 18 April 2026
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `current-date()` is not available in XSLT 1.0.
|
||||
- The value includes the processor's implicit timezone. Use `adjust-date-to-timezone()` to convert to a different offset.
|
||||
- To extract parts of the date, use `year-from-date()`, `month-from-date()`, or `day-from-date()`.
|
||||
- For a combined date and time, use `current-dateTime()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-time()](../xpath-current-time)
|
||||
- [current-dateTime()](../xpath-current-date-time)
|
||||
- [year-from-date()](../xpath-year-from-date)
|
||||
- [month-from-date()](../xpath-month-from-date)
|
||||
- [day-from-date()](../xpath-day-from-date)
|
||||
- [format-date()](../xpath-format-date)
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: "current-group()"
|
||||
description: "Returns the sequence of items in the current group inside an xsl:for-each-group instruction."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "current-group()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-group()` returns all the items that belong to the current group within an `<xsl:for-each-group>` instruction. It is only meaningful inside `xsl:for-each-group` — outside that instruction, the result is implementation-defined (typically the empty sequence).
|
||||
|
||||
Paired with `current-grouping-key()`, it gives you full access to both the grouping criterion and the grouped items.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the sequence of items in the current group.
|
||||
|
||||
## Examples
|
||||
|
||||
### Summarise sales by region
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sales>
|
||||
<sale region="north" amount="100"/>
|
||||
<sale region="south" amount="200"/>
|
||||
<sale region="north" amount="150"/>
|
||||
<sale region="east" amount="300"/>
|
||||
<sale region="south" amount="180"/>
|
||||
</sales>
|
||||
```
|
||||
|
||||
**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="/sales">
|
||||
<summary>
|
||||
<xsl:for-each-group select="sale" group-by="@region">
|
||||
<region name="{current-grouping-key()}">
|
||||
<count><xsl:value-of select="count(current-group())"/></count>
|
||||
<total><xsl:value-of select="sum(current-group()/xs:decimal(@amount))"/></total>
|
||||
</region>
|
||||
</xsl:for-each-group>
|
||||
</summary>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<summary>
|
||||
<region name="north"><count>2</count><total>250</total></region>
|
||||
<region name="south"><count>2</count><total>380</total></region>
|
||||
<region name="east"><count>1</count><total>300</total></region>
|
||||
</summary>
|
||||
```
|
||||
|
||||
### Wrap each group in a container element
|
||||
|
||||
**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="/employees">
|
||||
<departments>
|
||||
<xsl:for-each-group select="employee" group-by="@dept">
|
||||
<department name="{current-grouping-key()}">
|
||||
<xsl:copy-of select="current-group()"/>
|
||||
</department>
|
||||
</xsl:for-each-group>
|
||||
</departments>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `current-group()` is only valid inside `xsl:for-each-group`. Using it elsewhere is an error or returns the empty sequence depending on the processor.
|
||||
- The items in `current-group()` are a subset of the `select` expression of the enclosing `xsl:for-each-group`, in document order.
|
||||
- The context item inside `xsl:for-each-group` is the **first item** of the current group; `current-group()` gives you all items.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-grouping-key()](../xpath-current-grouping-key)
|
||||
- [xsl:for-each-group](../xsl-for-each-group)
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: "current-grouping-key()"
|
||||
description: "Returns the grouping key of the current group inside an xsl:for-each-group instruction."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "current-grouping-key()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-grouping-key()` returns the value of the grouping key for the current group within an `<xsl:for-each-group>` instruction. The type and value of the key corresponds to the result of evaluating the `group-by`, `group-adjacent`, `group-starting-with`, or `group-ending-with` attribute for the representative item of the current group.
|
||||
|
||||
It is only meaningful inside `xsl:for-each-group`. Outside that instruction, the result is implementation-defined.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyAtomicType?` — the grouping key of the current group, or the empty sequence when used with `group-starting-with` or `group-ending-with`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Group and label by category
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<products>
|
||||
<product category="electronics" name="Tablet"/>
|
||||
<product category="books" name="XSLT Guide"/>
|
||||
<product category="electronics" name="Laptop"/>
|
||||
<product category="books" name="XML Handbook"/>
|
||||
</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">
|
||||
<catalog>
|
||||
<xsl:for-each-group select="product" group-by="@category">
|
||||
<xsl:sort select="current-grouping-key()"/>
|
||||
<category id="{current-grouping-key()}">
|
||||
<xsl:for-each select="current-group()">
|
||||
<item><xsl:value-of select="@name"/></item>
|
||||
</xsl:for-each>
|
||||
</category>
|
||||
</xsl:for-each-group>
|
||||
</catalog>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<catalog>
|
||||
<category id="books">
|
||||
<item>XSLT Guide</item>
|
||||
<item>XML Handbook</item>
|
||||
</category>
|
||||
<category id="electronics">
|
||||
<item>Tablet</item>
|
||||
<item>Laptop</item>
|
||||
</category>
|
||||
</catalog>
|
||||
```
|
||||
|
||||
### Use the grouping key in a heading
|
||||
|
||||
**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="html" indent="yes"/>
|
||||
|
||||
<xsl:template match="/products">
|
||||
<html><body>
|
||||
<xsl:for-each-group select="product" group-by="@category">
|
||||
<h2><xsl:value-of select="current-grouping-key()"/></h2>
|
||||
<ul>
|
||||
<xsl:for-each select="current-group()">
|
||||
<li><xsl:value-of select="@name"/></li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</xsl:for-each-group>
|
||||
</body></html>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- For `group-starting-with` and `group-ending-with`, `current-grouping-key()` returns the empty sequence because these grouping methods do not use a key expression.
|
||||
- `current-grouping-key()` is only valid inside `xsl:for-each-group`. Using it elsewhere is an error.
|
||||
- When multiple keys are produced by a sequence-valued `group-by`, the key for the current group is the specific value that identified this group.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-group()](../xpath-current-group)
|
||||
- [xsl:for-each-group](../xsl-for-each-group)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: "current-merge-group()"
|
||||
description: "Returns the sequence of items in the current merge group inside an xsl:merge-action block."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "current-merge-group(source?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-merge-group()` is used inside the `xsl:merge-action` child of an `xsl:merge` instruction. It returns the sequence of items from the current merge group — that is, all items from one or more merge sources that share the same current merge key.
|
||||
|
||||
When `xsl:merge` processes multiple input streams simultaneously, it groups corresponding items by their computed merge key. Inside `xsl:merge-action`, `current-merge-group()` without an argument returns all items from all sources in the current group. When a `source` argument is supplied (the value of a `for-each-source` attribute or a source name), the function returns items only from that specific merge source.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `source` | xs:string | No | The name of the merge source to restrict the group to. Omit to get items from all sources. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the items in the current merge group, optionally restricted to a named source.
|
||||
|
||||
## Examples
|
||||
|
||||
### Merging two sorted lists
|
||||
|
||||
**Input XML (file1.xml):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<items>
|
||||
<item key="a">Alpha from source1</item>
|
||||
<item key="b">Beta from source1</item>
|
||||
</items>
|
||||
```
|
||||
|
||||
**Input XML (file2.xml):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<items>
|
||||
<item key="a">Alpha from source2</item>
|
||||
<item key="c">Gamma from source2</item>
|
||||
</items>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<merged>
|
||||
<xsl:merge>
|
||||
<xsl:merge-source name="s1" select="doc('file1.xml')/items/item">
|
||||
<xsl:merge-key select="@key"/>
|
||||
</xsl:merge-source>
|
||||
<xsl:merge-source name="s2" select="doc('file2.xml')/items/item">
|
||||
<xsl:merge-key select="@key"/>
|
||||
</xsl:merge-source>
|
||||
<xsl:merge-action>
|
||||
<group key="{current-merge-key()}">
|
||||
<xsl:for-each select="current-merge-group()">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</group>
|
||||
</xsl:merge-action>
|
||||
</xsl:merge>
|
||||
</merged>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<merged>
|
||||
<group key="a">
|
||||
<item>Alpha from source1</item>
|
||||
<item>Alpha from source2</item>
|
||||
</group>
|
||||
<group key="b">
|
||||
<item>Beta from source1</item>
|
||||
</group>
|
||||
<group key="c">
|
||||
<item>Gamma from source2</item>
|
||||
</group>
|
||||
</merged>
|
||||
```
|
||||
|
||||
### Reading from a specific source
|
||||
|
||||
**Stylesheet snippet:**
|
||||
```xml
|
||||
<xsl:merge-action>
|
||||
<!-- Only items from source s1 -->
|
||||
<xsl:for-each select="current-merge-group('s1')">
|
||||
<s1-item><xsl:value-of select="."/></s1-item>
|
||||
</xsl:for-each>
|
||||
</xsl:merge-action>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `current-merge-group()` is only valid inside the `xsl:merge-action` element; using it elsewhere raises a static error.
|
||||
- Without an argument, it returns items from all named merge sources combined.
|
||||
- The merge sources must provide pre-sorted input or declare sort keys via `xsl:merge-key` for `xsl:merge` to operate correctly.
|
||||
- `current-merge-group()` and `current-merge-key()` are the two functions designed specifically for use inside `xsl:merge-action`.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-merge-key()](../xpath-current-merge-key)
|
||||
- [xsl:use-accumulators](../xsl-use-accumulators)
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: "current-merge-key()"
|
||||
description: "Returns the current merge key value inside an xsl:merge-action block."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "current-merge-key()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-merge-key()` returns the value of the merge key for the current group being processed inside an `xsl:merge-action` block. When `xsl:merge` groups items from one or more sources by their computed key, `current-merge-key()` provides the key value shared by all items in the current group.
|
||||
|
||||
The returned value is an atomic value or a sequence of atomic values corresponding to the `xsl:merge-key` expressions declared in the merge sources. When multiple keys are declared (composite keys), the function returns a sequence of values — one per key component — in declaration order.
|
||||
|
||||
`current-merge-key()` is the merge equivalent of `current-grouping-key()` from `xsl:for-each-group`.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyAtomicType+` — the merge key value(s) for the current group.
|
||||
|
||||
## Examples
|
||||
|
||||
### Displaying the merge key in output
|
||||
|
||||
**Input XML (employees.xml):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<employees>
|
||||
<emp dept="HR" name="Alice"/>
|
||||
<emp dept="IT" name="Bob"/>
|
||||
<emp dept="HR" name="Carol"/>
|
||||
</employees>
|
||||
```
|
||||
|
||||
**Input XML (salaries.xml):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<salaries>
|
||||
<sal dept="HR" amount="50000"/>
|
||||
<sal dept="IT" amount="75000"/>
|
||||
</salaries>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<departments>
|
||||
<xsl:merge>
|
||||
<xsl:merge-source name="emps"
|
||||
select="doc('employees.xml')/employees/emp">
|
||||
<xsl:merge-key select="@dept" order="ascending"/>
|
||||
</xsl:merge-source>
|
||||
<xsl:merge-source name="sals"
|
||||
select="doc('salaries.xml')/salaries/sal">
|
||||
<xsl:merge-key select="@dept" order="ascending"/>
|
||||
</xsl:merge-source>
|
||||
<xsl:merge-action>
|
||||
<dept name="{current-merge-key()}">
|
||||
<xsl:for-each select="current-merge-group('emps')">
|
||||
<employee name="{@name}"/>
|
||||
</xsl:for-each>
|
||||
<xsl:for-each select="current-merge-group('sals')">
|
||||
<salary amount="{@amount}"/>
|
||||
</xsl:for-each>
|
||||
</dept>
|
||||
</xsl:merge-action>
|
||||
</xsl:merge>
|
||||
</departments>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<departments>
|
||||
<dept name="HR">
|
||||
<employee name="Alice"/>
|
||||
<employee name="Carol"/>
|
||||
<salary amount="50000"/>
|
||||
</dept>
|
||||
<dept name="IT">
|
||||
<employee name="Bob"/>
|
||||
<salary amount="75000"/>
|
||||
</dept>
|
||||
</departments>
|
||||
```
|
||||
|
||||
### Using the key in a conditional
|
||||
|
||||
**Stylesheet snippet:**
|
||||
```xml
|
||||
<xsl:merge-action>
|
||||
<xsl:if test="current-merge-key() = 'IT'">
|
||||
<tech-dept>
|
||||
<xsl:copy-of select="current-merge-group()"/>
|
||||
</tech-dept>
|
||||
</xsl:if>
|
||||
</xsl:merge-action>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `current-merge-key()` is only valid inside the `xsl:merge-action` element.
|
||||
- For composite merge keys (multiple `xsl:merge-key` declarations), the function returns a sequence of atomic values in declaration order.
|
||||
- The key type is determined by the key expression; string, numeric, date, and other atomic types are all supported.
|
||||
- This function is the merge counterpart to `current-grouping-key()` used with `xsl:for-each-group`.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-merge-group()](../xpath-current-merge-group)
|
||||
- [xsl:use-accumulators](../xsl-use-accumulators)
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
title: "current-output-uri()"
|
||||
description: "Returns the URI of the current result document being written inside an xsl:result-document instruction."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "current-output-uri()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-output-uri()` returns the URI of the result document currently being written — the `href` value of the enclosing `<xsl:result-document>` instruction. Outside an `xsl:result-document`, it returns the empty sequence.
|
||||
|
||||
This is useful for embedding a document's own URI as metadata within itself, logging which file is being generated, or constructing relative cross-references between generated documents.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyURI?` — the URI of the current result document, or the empty sequence when called outside `xsl:result-document`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Embed the output URI in each generated document
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapters>
|
||||
<chapter id="ch1" title="Introduction"/>
|
||||
<chapter id="ch2" title="Getting Started"/>
|
||||
</chapters>
|
||||
```
|
||||
|
||||
**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="/chapters">
|
||||
<xsl:for-each select="chapter">
|
||||
<xsl:result-document href="{@id}.xml">
|
||||
<chapter id="{@id}"
|
||||
self-uri="{current-output-uri()}">
|
||||
<title><xsl:value-of select="@title"/></title>
|
||||
</chapter>
|
||||
</xsl:result-document>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (ch1.xml):**
|
||||
```xml
|
||||
<chapter id="ch1" self-uri="ch1.xml">
|
||||
<title>Introduction</title>
|
||||
</chapter>
|
||||
```
|
||||
|
||||
### Log generated file names to the principal output
|
||||
|
||||
**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="/chapters">
|
||||
<manifest>
|
||||
<xsl:for-each select="chapter">
|
||||
<xsl:result-document href="{@id}.xml">
|
||||
<chapter/>
|
||||
</xsl:result-document>
|
||||
<file><xsl:value-of select="concat(@id, '.xml')"/></file>
|
||||
</xsl:for-each>
|
||||
</manifest>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Returns the empty sequence when called in the principal result tree (outside any `xsl:result-document`).
|
||||
- The returned URI is the value of the `href` attribute of the enclosing `xsl:result-document`, resolved against the static base URI if it is relative.
|
||||
- Useful for generating self-referential metadata in split-document outputs.
|
||||
|
||||
## See also
|
||||
|
||||
- [static-base-uri()](../xpath-static-base-uri)
|
||||
- [document-uri()](../xpath-document-uri)
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: "current-time()"
|
||||
description: "Returns the current time as an xs:time value, stable and fixed for the duration of the transformation."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "current-time()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`current-time()` returns the current time as an `xs:time` value, including the implicit timezone of the processor. Like `current-date()` and `current-dateTime()`, the value is **fixed** for the entire transformation: repeated calls return the same time, guaranteeing a consistent timestamp throughout the output.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:time` — the current time in the form `HH:MM:SS.sss+HH:MM` (with timezone offset). Stable for the lifetime of the transformation.
|
||||
|
||||
## Examples
|
||||
|
||||
### Embed the generation time in output
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feed>
|
||||
<item>First item</item>
|
||||
<item>Second item</item>
|
||||
</feed>
|
||||
```
|
||||
|
||||
**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="/feed">
|
||||
<feed generated-time="{current-time()}">
|
||||
<xsl:copy-of select="*"/>
|
||||
</feed>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```xml
|
||||
<feed generated-time="14:32:07.123+01:00">
|
||||
<item>First item</item>
|
||||
<item>Second item</item>
|
||||
</feed>
|
||||
```
|
||||
|
||||
### Format the current time for display
|
||||
|
||||
**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-time(current-time(), '[H01]:[m01]:[s01]')"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```
|
||||
14:32:07
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Not available in XSLT 1.0.
|
||||
- The value includes the processor's implicit timezone. Pair with `adjust-time-to-timezone()` to normalise to UTC or another offset.
|
||||
- To extract individual components, use `hours-from-time()`, `minutes-from-time()`, or `seconds-from-time()`.
|
||||
- For a combined date and time, use `current-dateTime()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-date()](../xpath-current-date)
|
||||
- [current-dateTime()](../xpath-current-date-time)
|
||||
- [hours-from-time()](../xpath-hours-from-time)
|
||||
- [minutes-from-time()](../xpath-minutes-from-time)
|
||||
- [seconds-from-time()](../xpath-seconds-from-time)
|
||||
- [format-time()](../xpath-format-time)
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: "day-from-date()"
|
||||
description: "Extracts the day-of-month component from an xs:date value as an xs:integer in the range 1–31."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "day-from-date(date)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`day-from-date()` returns the day-of-month component of an `xs:date` value as an `xs:integer` between 1 and 31. If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `date` | xs:date? | Yes | The date value from which to extract the day. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer?` — integer from 1 to 31 representing the day of the month, or the empty sequence if the argument is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Display a formatted date with separate components
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<invoice>
|
||||
<issued>2026-04-18</issued>
|
||||
<due>2026-05-18</due>
|
||||
</invoice>
|
||||
```
|
||||
|
||||
**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="/invoice">
|
||||
<invoice>
|
||||
<xsl:for-each select="issued|due">
|
||||
<xsl:element name="{local-name()}">
|
||||
<day><xsl:value-of select="day-from-date(xs:date(.))"/></day>
|
||||
<month><xsl:value-of select="month-from-date(xs:date(.))"/></month>
|
||||
<year><xsl:value-of select="year-from-date(xs:date(.))"/></year>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
</invoice>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<invoice>
|
||||
<issued>
|
||||
<day>18</day>
|
||||
<month>4</month>
|
||||
<year>2026</year>
|
||||
</issued>
|
||||
<due>
|
||||
<day>18</day>
|
||||
<month>5</month>
|
||||
<year>2026</year>
|
||||
</due>
|
||||
</invoice>
|
||||
```
|
||||
|
||||
### Find events on the 1st of any month
|
||||
|
||||
**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">
|
||||
<first-of-month>
|
||||
<xsl:copy-of select="event[day-from-date(xs:date(@date)) = 1]"/>
|
||||
</first-of-month>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The argument must be typed as `xs:date`. Cast string values with `xs:date(.)` or `xs:date(@attr)`.
|
||||
- Returns 1–31 depending on the month; it does not validate whether the day is valid for the given month (that is enforced when constructing the `xs:date` value).
|
||||
- For `xs:dateTime` values, use `day-from-dateTime()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [year-from-date()](../xpath-year-from-date)
|
||||
- [month-from-date()](../xpath-month-from-date)
|
||||
- [current-date()](../xpath-current-date)
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: "deep-equal()"
|
||||
description: "Returns true if two sequences are deeply equal: same items in the same order with equal node identity or atomic values."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "sequence function"
|
||||
syntax: "deep-equal(sequence1, sequence2, collation?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`deep-equal()` compares two sequences item by item. Two sequences are deeply equal if they have the same length and each pair of corresponding items is deeply equal. For atomic values, deep equality uses the same comparison as `=` with type promotion. For nodes, deep equality means the nodes have the same kind, name, and — recursively — the same children, attributes, and text content.
|
||||
|
||||
The optional `collation` argument controls string comparison. When omitted, the default collation is used. This makes `deep-equal()` suitable for locale-aware comparisons of mixed sequences containing strings.
|
||||
|
||||
`deep-equal()` never raises an error for incompatible types: comparing an integer to a string returns `false` rather than a type error, which distinguishes it from the `=` operator.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence1` | item()* | Yes | The first sequence to compare. |
|
||||
| `sequence2` | item()* | Yes | The second sequence to compare. |
|
||||
| `collation` | xs:string | No | URI of the collation used for string comparison. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the sequences are deeply equal, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Comparing two element subtrees
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<a><x>1</x><y>2</y></a>
|
||||
<b><x>1</x><y>2</y></b>
|
||||
<c><x>1</x><y>3</y></c>
|
||||
</root>
|
||||
```
|
||||
|
||||
**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="/root">
|
||||
<results>
|
||||
<ab><xsl:value-of select="deep-equal(a, b)"/></ab>
|
||||
<ac><xsl:value-of select="deep-equal(a, c)"/></ac>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<ab>true</ab>
|
||||
<ac>false</ac>
|
||||
</results>
|
||||
```
|
||||
|
||||
### Comparing sequences of atomic values
|
||||
|
||||
**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="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="s1" select="(1, 2, 3)"/>
|
||||
<xsl:variable name="s2" select="(1, 2, 3)"/>
|
||||
<xsl:variable name="s3" select="(1, 2, 4)"/>
|
||||
<xsl:value-of select="deep-equal($s1, $s2)"/><xsl:text> </xsl:text>
|
||||
<xsl:value-of select="deep-equal($s1, $s3)"/><xsl:text> </xsl:text>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
true
|
||||
false
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `deep-equal()` compares attributes regardless of document order for element nodes. Two elements with the same attributes in a different order are still deeply equal.
|
||||
- Namespace nodes, processing instructions, and comments are included in the comparison when they are present in the node's children.
|
||||
- The function is particularly useful in unit tests and validation stylesheets where you need to assert that a transformation produced an expected XML structure.
|
||||
- An empty sequence is deeply equal only to another empty sequence.
|
||||
|
||||
## See also
|
||||
|
||||
- [empty()](../xpath-empty)
|
||||
- [count()](../xpath-count)
|
||||
- [exactly-one()](../xpath-exactly-one)
|
||||
@@ -0,0 +1,130 @@
|
||||
---
|
||||
title: "distinct-values()"
|
||||
description: "Returns a sequence containing only the distinct values from the input sequence, removing duplicates using value equality."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "sequence function"
|
||||
syntax: "distinct-values(sequence, collation?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`distinct-values()` removes duplicate atomic values from a sequence, retaining one representative from each group of equal values. The order of retained values follows the order of first occurrence in the input sequence.
|
||||
|
||||
Equality is determined by value semantics (not identity): for strings, the default Unicode codepoint collation is used unless a different `collation` URI is provided; for numeric types, numeric equality applies (so `1` and `1.0` are equal).
|
||||
|
||||
The function works on atomic values only. If the input contains nodes, their typed values (strings) are compared — not the nodes themselves.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | xs:anyAtomicType* | Yes | The sequence to deduplicate. |
|
||||
| `collation` | xs:string | No | A collation URI for string comparison. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyAtomicType*` — the sequence with duplicates removed, preserving first-occurrence order.
|
||||
|
||||
## Examples
|
||||
|
||||
### Getting unique categories
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<products>
|
||||
<product category="Fruit">Apple</product>
|
||||
<product category="Vegetable">Carrot</product>
|
||||
<product category="Fruit">Banana</product>
|
||||
<product category="Grain">Rice</product>
|
||||
<product category="Vegetable">Broccoli</product>
|
||||
<product category="Fruit">Cherry</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">
|
||||
<categories>
|
||||
<xsl:for-each select="distinct-values(product/@category)">
|
||||
<xsl:sort select="."/>
|
||||
<category><xsl:value-of select="."/></category>
|
||||
</xsl:for-each>
|
||||
</categories>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<categories>
|
||||
<category>Fruit</category>
|
||||
<category>Grain</category>
|
||||
<category>Vegetable</category>
|
||||
</categories>
|
||||
```
|
||||
|
||||
### Counting unique authors across articles
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<library>
|
||||
<article author="Alice">Article 1</article>
|
||||
<article author="Bob">Article 2</article>
|
||||
<article author="Alice">Article 3</article>
|
||||
<article author="Carol">Article 4</article>
|
||||
<article author="Bob">Article 5</article>
|
||||
</library>
|
||||
```
|
||||
|
||||
**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="/library">
|
||||
<xsl:variable name="unique-authors"
|
||||
select="distinct-values(article/@author)"/>
|
||||
<stats>
|
||||
<unique-authors count="{count($unique-authors)}">
|
||||
<xsl:for-each select="$unique-authors">
|
||||
<author><xsl:value-of select="."/></author>
|
||||
</xsl:for-each>
|
||||
</unique-authors>
|
||||
</stats>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<stats>
|
||||
<unique-authors count="3">
|
||||
<author>Alice</author>
|
||||
<author>Bob</author>
|
||||
<author>Carol</author>
|
||||
</unique-authors>
|
||||
</stats>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `distinct-values()` operates on atomic values, not nodes. If you apply it to element nodes, their string values are compared. If you need to group and deduplicate by element identity, use `xsl:for-each-group` with `group-by`.
|
||||
- For grouping with the ability to access all members of each group, `xsl:for-each-group` is more appropriate than `distinct-values()`.
|
||||
- Numeric type coercion applies: `distinct-values((1, 1.0, 1e0))` may return just one item, since all are numerically equal.
|
||||
- The order of results is the order of first occurrence — it is not sorted. Add `xsl:sort` or `sort()` to sort the output.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:for-each-group](../xsl-for-each-group)
|
||||
- [index-of()](../xpath-index-of)
|
||||
- [count()](../xpath-count)
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
title: "document-uri()"
|
||||
description: "Returns the URI of the document node that contains the given node, as an xs:anyURI."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "document-uri(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`document-uri()` returns the URI used to load the document containing the given node. Unlike `base-uri()`, it returns the URI of the **document node** itself and is not affected by `xml:base` attributes on descendant elements.
|
||||
|
||||
When called without an argument, the context node is used. If the argument is the empty sequence or the node has no document URI (e.g., it was constructed in memory), the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node()? | No | The node whose document URI is requested. Defaults to the context node. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyURI?` — the URI of the document node, or the empty sequence if no URI is available.
|
||||
|
||||
## Examples
|
||||
|
||||
### Report the document URI of a loaded document
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<info>
|
||||
<source-uri><xsl:value-of select="document-uri(.)"/></source-uri>
|
||||
</info>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```xml
|
||||
<info>
|
||||
<source-uri>file:///data/input.xml</source-uri>
|
||||
</info>
|
||||
```
|
||||
|
||||
### Load and track multiple documents
|
||||
|
||||
**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="/catalog">
|
||||
<sources>
|
||||
<xsl:for-each select="item/@href">
|
||||
<xsl:variable name="doc" select="document(.)"/>
|
||||
<source uri="{document-uri($doc)}">
|
||||
<xsl:value-of select="$doc/*/title"/>
|
||||
</source>
|
||||
</xsl:for-each>
|
||||
</sources>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `document-uri()` returns the URI of the **document root**, not an element's base URI. For the effective base URI (considering `xml:base`), use `base-uri()`.
|
||||
- For nodes created via `parse-xml()` or result tree fragments, the document URI is typically absent (empty sequence).
|
||||
- The function was introduced in XPath 2.0 and is not available in XSLT 1.0.
|
||||
|
||||
## See also
|
||||
|
||||
- [base-uri()](../xpath-base-uri)
|
||||
- [static-base-uri()](../xpath-static-base-uri)
|
||||
- [parse-xml()](../xpath-parse-xml)
|
||||
@@ -0,0 +1,126 @@
|
||||
---
|
||||
title: "document()"
|
||||
description: "Loads an external XML document by URI and returns its root node as a node-set, enabling multi-document transformations in XSLT 1.0."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "document(uri, node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`document()` retrieves an external XML document and returns it as a node-set containing the document root. This is the primary mechanism in XSLT 1.0 for accessing data from multiple sources within a single transformation.
|
||||
|
||||
The first argument can be:
|
||||
- A **string** URI — the document at that URI is loaded and returned as a single-item node-set.
|
||||
- A **node-set** — each node is converted to its string value (treated as a URI), the corresponding documents are loaded, and their root nodes are returned as a combined node-set.
|
||||
|
||||
The optional second argument is a node from which the base URI for resolving relative URIs is taken. If omitted, relative URIs are resolved against the base URI of the stylesheet.
|
||||
|
||||
Calling `document('')` is a special idiom: it returns the root of the **stylesheet document itself**, allowing stylesheet data to be embedded as XML and accessed from templates.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `uri` | xs:string or node-set | Yes | URI of the external document, or a node-set of URI-valued nodes. |
|
||||
| `node` | node-set | No | Node whose base URI is used to resolve relative URIs in the first argument. |
|
||||
|
||||
## Return value
|
||||
|
||||
`node-set` — the root nodes of the loaded document(s).
|
||||
|
||||
## Examples
|
||||
|
||||
### Load an external lookup document
|
||||
|
||||
**External file: `colors.xml`**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<colors>
|
||||
<color code="R">Red</color>
|
||||
<color code="G">Green</color>
|
||||
<color code="B">Blue</color>
|
||||
</colors>
|
||||
```
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<items>
|
||||
<item color="R">Apple</item>
|
||||
<item color="G">Leaf</item>
|
||||
<item color="B">Sky</item>
|
||||
</items>
|
||||
```
|
||||
|
||||
**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:variable name="colors" select="document('colors.xml')/colors"/>
|
||||
|
||||
<xsl:template match="/items">
|
||||
<result>
|
||||
<xsl:for-each select="item">
|
||||
<xsl:variable name="code" select="@color"/>
|
||||
<item color="{$colors/color[@code=$code]}">
|
||||
<xsl:value-of select="."/>
|
||||
</item>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<item color="Red">Apple</item>
|
||||
<item color="Green">Leaf</item>
|
||||
<item color="Blue">Sky</item>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Embed data in the stylesheet using document('')
|
||||
|
||||
**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"/>
|
||||
|
||||
<!-- Embedded lookup table -->
|
||||
<lookup xmlns="">
|
||||
<entry key="1" label="One"/>
|
||||
<entry key="2" label="Two"/>
|
||||
<entry key="3" label="Three"/>
|
||||
</lookup>
|
||||
|
||||
<xsl:variable name="lookup" select="document('')/*/lookup"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<labels>
|
||||
<xsl:for-each select="item">
|
||||
<label><xsl:value-of select="$lookup/entry[@key=current()/@id]/@label"/></label>
|
||||
</xsl:for-each>
|
||||
</labels>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The behavior when the referenced document cannot be found is processor-specific: some processors raise a fatal error, others return an empty node-set. Check processor documentation.
|
||||
- `document('')` returns the stylesheet document; combine with an XPath expression to navigate to embedded data elements.
|
||||
- Relative URIs are resolved against the **stylesheet** base URI by default, not the source document URI. Use the second argument to change the base.
|
||||
- In XSLT 2.0+, `document()` is superseded by the `fn:doc()` and `fn:collection()` functions, which integrate with XPath 2.0's type system.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:import](../xsl-import)
|
||||
- [xsl:include](../xsl-include)
|
||||
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: "element-available()"
|
||||
description: "Returns true if the named XSLT instruction or extension element is supported by the processor, enabling portable fallback branches."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "element-available(name)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`element-available()` tests whether the XSLT processor supports a named instruction element and returns a boolean. The argument is a string containing a QName; if the QName is in the `xsl:` namespace, it tests for a standard XSLT instruction. If it is in another namespace, it tests for a processor-specific extension element.
|
||||
|
||||
The function is intended for use inside `xsl:choose`/`xsl:when` or `xsl:if` to branch between implementations depending on what the current processor supports. Combined with `xsl:fallback`, it provides a portable way to use extension elements with graceful degradation.
|
||||
|
||||
Only elements that appear as **children of the stylesheet** (i.e. XSLT instructions and extension elements, not result elements) are tested. Testing for an arbitrary user-defined element name that is not an instruction always returns `false`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | xs:string | Yes | A QName string naming the element to test. The namespace prefix must be in scope. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the element is available, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Test for a standard XSLT instruction
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data><item>A</item><item>B</item></data>
|
||||
```
|
||||
|
||||
**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="/data">
|
||||
<info>
|
||||
<for-each-available>
|
||||
<xsl:value-of select="element-available('xsl:for-each')"/>
|
||||
</for-each-available>
|
||||
<nonexistent-available>
|
||||
<xsl:value-of select="element-available('xsl:nonexistent')"/>
|
||||
</nonexistent-available>
|
||||
</info>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<info>
|
||||
<for-each-available>true</for-each-available>
|
||||
<nonexistent-available>false</nonexistent-available>
|
||||
</info>
|
||||
```
|
||||
|
||||
### Guard use of an extension element
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:ext="http://exslt.org/common"
|
||||
extension-element-prefixes="ext">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/data">
|
||||
<result>
|
||||
<xsl:choose>
|
||||
<xsl:when test="element-available('ext:document')">
|
||||
<!-- Use EXSLT extension to write multiple output files -->
|
||||
<message>Multi-document output supported.</message>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<message>Multi-document output not supported; writing single file.</message>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `element-available()` only tests **XSLT instructions** and **extension elements**. It does not test for result element names (elements in no namespace or a non-XSLT namespace that become part of the output tree).
|
||||
- The prefix in the QName string must be declared in the stylesheet's namespace context; otherwise the function raises an error.
|
||||
- Standard XSLT 1.0 instructions (e.g. `xsl:for-each`, `xsl:if`, `xsl:choose`) always return `true` in a conformant XSLT 1.0 processor.
|
||||
- In XSLT 2.0+, the function is unchanged. It can be used to test for XSLT 2.0 instructions (e.g. `xsl:for-each-group`) when running under a processor that may be in XSLT 1.0 compatibility mode.
|
||||
|
||||
## See also
|
||||
|
||||
- [function-available()](../xpath-function-available)
|
||||
- [system-property()](../xpath-system-property)
|
||||
- [xsl:fallback](../xsl-fallback)
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: "empty()"
|
||||
description: "Returns true if the sequence has zero items, and false if it contains one or more items."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "sequence function"
|
||||
syntax: "empty(sequence)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`empty()` tests whether a sequence contains no items. It is the logical complement of `exists()`: `empty($s)` is equivalent to `not(exists($s))` and to `count($s) = 0`, but is more readable and may be more efficient because the processor can stop as soon as it finds any item.
|
||||
|
||||
The sequence argument may be any XPath expression — a node selection, a function result, or a constructed sequence.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The sequence to test. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the sequence is empty, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Checking for missing child elements
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<catalog>
|
||||
<product id="A"><name>Alpha</name><tags><tag>xml</tag></tags></product>
|
||||
<product id="B"><name>Beta</name><tags/></product>
|
||||
<product id="C"><name>Gamma</name></product>
|
||||
</catalog>
|
||||
```
|
||||
|
||||
**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="/catalog">
|
||||
<report>
|
||||
<xsl:for-each select="product">
|
||||
<product id="{@id}"
|
||||
has-tags="{if (empty(tags/tag)) then 'no' else 'yes'}">
|
||||
<xsl:value-of select="name"/>
|
||||
</product>
|
||||
</xsl:for-each>
|
||||
</report>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<report>
|
||||
<product id="A" has-tags="yes">Alpha</product>
|
||||
<product id="B" has-tags="no">Beta</product>
|
||||
<product id="C" has-tags="no">Gamma</product>
|
||||
</report>
|
||||
```
|
||||
|
||||
### Providing a default when a sequence is empty
|
||||
|
||||
**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">
|
||||
<xsl:variable name="items" select="item[@active='true']"/>
|
||||
<result>
|
||||
<xsl:choose>
|
||||
<xsl:when test="empty($items)">
|
||||
<message>No active items found.</message>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:for-each select="$items">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `empty($seq)` is semantically equivalent to `not($seq)` for sequences, but is preferred for clarity when working with typed sequences.
|
||||
- For node selections, `empty(//foo)` is more readable than `not(//foo)`, especially in predicate contexts.
|
||||
- `empty()` short-circuits: it does not need to evaluate the entire sequence; it stops at the first item.
|
||||
- Use `exists()` to test the positive case; avoid double negation with `not(empty(...))`.
|
||||
|
||||
## See also
|
||||
|
||||
- [exists()](../xpath-exists)
|
||||
- [count()](../xpath-count)
|
||||
- [zero-or-one()](../xpath-zero-or-one)
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: "ends-with()"
|
||||
description: "Returns true if the first string ends with the second string, using optional collation for comparison."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "ends-with(string, suffix)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`ends-with()` tests whether the string in the first argument ends with the string in the second argument. It returns `true` if the suffix matches, `false` otherwise.
|
||||
|
||||
The comparison uses codepoint-by-codepoint equality by default (same as XPath's `=` operator on strings). In XPath 2.0 a third `collation` argument is allowed for locale-sensitive suffix testing, though most processors default to the Unicode codepoint collation.
|
||||
|
||||
If either argument is an empty string `""`, special rules apply: any string ends with `""` (always `true`), and `""` ends with `""` (also `true`).
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string? | Yes | The string to test. |
|
||||
| `suffix` | xs:string? | Yes | The suffix to look for at the end of `string`. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if `string` ends with `suffix`, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Filtering files by extension
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files>
|
||||
<file>report.pdf</file>
|
||||
<file>data.xml</file>
|
||||
<file>summary.pdf</file>
|
||||
<file>stylesheet.xsl</file>
|
||||
<file>notes.txt</file>
|
||||
</files>
|
||||
```
|
||||
|
||||
**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="/files">
|
||||
<pdf-files>
|
||||
<xsl:for-each select="file[ends-with(., '.pdf')]">
|
||||
<file><xsl:value-of select="."/></file>
|
||||
</xsl:for-each>
|
||||
</pdf-files>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<pdf-files>
|
||||
<file>report.pdf</file>
|
||||
<file>summary.pdf</file>
|
||||
</pdf-files>
|
||||
```
|
||||
|
||||
### Checking namespace URIs
|
||||
|
||||
**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="/namespaces">
|
||||
<xhtml-ns>
|
||||
<!-- Select namespace nodes whose URI ends with 'xhtml' -->
|
||||
<xsl:for-each select="ns[ends-with(@uri, 'xhtml')]">
|
||||
<match prefix="{@prefix}" uri="{@uri}"/>
|
||||
</xsl:for-each>
|
||||
</xhtml-ns>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `ends-with()` was introduced in XPath 2.0. In XPath 1.0 there is no built-in equivalent; the workaround is `substring($s, string-length($s) - string-length($suffix) + 1) = $suffix`.
|
||||
- The comparison is case-sensitive by default. For case-insensitive suffix testing, normalize both strings with `lower-case()` first.
|
||||
- An empty `suffix` always returns `true`. An empty `string` with a non-empty `suffix` returns `false`.
|
||||
- `starts-with()` (available in both XPath 1.0 and 2.0) is the complementary function for prefix testing.
|
||||
|
||||
## See also
|
||||
|
||||
- [starts-with()](../xpath-starts-with)
|
||||
- [contains()](../xpath-contains)
|
||||
- [substring()](../xpath-substring)
|
||||
- [lower-case()](../xpath-lower-case)
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: "environment-variable()"
|
||||
description: "Returns the value of the named environment variable as a string, or the empty sequence if unavailable."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "environment-variable(name)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`environment-variable()` retrieves the value of a named operating-system or processor-defined environment variable. The function returns the value as a string if the variable is set and accessible, or the empty sequence if it is not available.
|
||||
|
||||
Processors are not required to expose any particular environment variables, and they may choose to expose none at all for security reasons. Use `available-environment-variables()` to discover which variables are accessible before calling this function. The function raises no error when a variable is absent — it simply returns the empty sequence, which can be tested with `exists()` or `empty()`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | xs:string | Yes | The name of the environment variable to retrieve. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string?` — the value of the environment variable, or the empty sequence if the variable is not set or not accessible.
|
||||
|
||||
## Examples
|
||||
|
||||
### Using an environment variable as a default
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/config">
|
||||
<xsl:variable name="home" select="environment-variable('HOME')"/>
|
||||
<settings>
|
||||
<home><xsl:value-of select="($home, 'unknown')[1]"/></home>
|
||||
<user><xsl:value-of select="(environment-variable('USER'), 'anonymous')[1]"/></user>
|
||||
</settings>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (on a Unix system):**
|
||||
```xml
|
||||
<settings>
|
||||
<home>/home/username</home>
|
||||
<user>username</user>
|
||||
</settings>
|
||||
```
|
||||
|
||||
### Checking availability before reading
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:choose>
|
||||
<xsl:when test="exists(environment-variable('APP_ENV'))">
|
||||
Environment: <xsl:value-of select="environment-variable('APP_ENV')"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
APP_ENV not set — using defaults
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
APP_ENV not set — using defaults
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Whether environment variables are accessible depends entirely on the processor implementation and security configuration. Saxon exposes OS environment variables by default, but this can be disabled.
|
||||
- The function is read-only; there is no mechanism in XPath/XSLT to set environment variables.
|
||||
- Environment variable names are case-sensitive on Unix-like systems and case-insensitive on Windows.
|
||||
- For production stylesheets, prefer XSLT parameters (`xsl:param`) over environment variables, as parameters are more portable and explicit.
|
||||
|
||||
## See also
|
||||
|
||||
- [available-environment-variables()](../xpath-available-environment-variables)
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: "error()"
|
||||
description: "Raises a dynamic error with an optional error code, description message, and error object."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "error(code?, description?, object?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`error()` raises a dynamic error unconditionally when evaluated. The transformation is aborted unless the error is caught by an `xsl:try/xsl:catch` block (XSLT 3.0). The function is useful for asserting preconditions, documenting unreachable code branches, and raising structured errors with well-defined error codes.
|
||||
|
||||
All three arguments are optional. When called with no arguments, a generic error (`FOER0000`) is raised. When `code` is supplied it must be a `QName` such as `QName('http://example.com/errors', 'e:InvalidInput')`. The `description` is a human-readable string. The `object` is an arbitrary item sequence attached to the error for diagnostic purposes.
|
||||
|
||||
Because `error()` never returns a value, it can be used in any XPath context, including the middle of a conditional expression.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `code` | xs:QName? | No | A QName identifying the error type; defaults to `FOER0000`. |
|
||||
| `description` | xs:string? | No | A human-readable description of the error. |
|
||||
| `object` | item()* | No | Arbitrary diagnostic data attached to the error. |
|
||||
|
||||
## Return value
|
||||
|
||||
`error()` never returns; it always raises a dynamic error.
|
||||
|
||||
## Examples
|
||||
|
||||
### Guarding an invalid input
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<request>
|
||||
<age>-5</age>
|
||||
</request>
|
||||
```
|
||||
|
||||
**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="/request">
|
||||
<xsl:variable name="age" select="xs:integer(age)"/>
|
||||
<xsl:if test="$age lt 0">
|
||||
<xsl:value-of select="error((), concat('Age must be non-negative, got: ', $age))"/>
|
||||
</xsl:if>
|
||||
<result age="{$age}"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (transformation aborted):**
|
||||
```
|
||||
Dynamic error: Age must be non-negative, got: -5
|
||||
```
|
||||
|
||||
### Catching an error in XSLT 3.0
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:err="http://www.w3.org/2005/xqt-errors"
|
||||
xmlns:app="http://example.com/errors">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<result>
|
||||
<xsl:try>
|
||||
<xsl:value-of select="error(QName('http://example.com/errors','app:NotFound'), 'Resource missing')"/>
|
||||
<xsl:catch errors="app:NotFound">
|
||||
<warning code="{$err:code}"><xsl:value-of select="$err:description"/></warning>
|
||||
</xsl:catch>
|
||||
</xsl:try>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<warning code="app:NotFound">Resource missing</warning>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `error()` with no arguments raises `FOER0000`; this is the XPath equivalent of an unspecified runtime exception.
|
||||
- In XSLT 1.0, `xsl:message terminate="yes"` is the closest equivalent since `error()` is not available.
|
||||
- The `object` argument is accessible as `$err:value` inside an `xsl:catch` block in XSLT 3.0.
|
||||
- `error()` is typed as returning `none`, which means it is type-compatible with any return type and can appear in the branch of an `if` expression without causing a type error.
|
||||
|
||||
## See also
|
||||
|
||||
- [xsl:message](../xsl-message)
|
||||
- [trace()](../xpath-trace)
|
||||
- [exactly-one()](../xpath-exactly-one)
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: "exactly-one()"
|
||||
description: "Asserts that the sequence contains exactly one item; raises a dynamic error if the sequence has zero or more than one item."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "sequence function"
|
||||
syntax: "exactly-one(sequence)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`exactly-one()` is a cardinality assertion function. It returns its argument unchanged if the sequence contains exactly one item, and raises a dynamic error (`FORG0005`) if the sequence is empty or contains more than one item.
|
||||
|
||||
Use `exactly-one()` to make cardinality assumptions explicit in your stylesheets. Rather than silently processing zero or multiple nodes when you expect exactly one, the function causes a clear error with a meaningful location. This is particularly valuable for enforcing schema-like constraints when schema validation is not available.
|
||||
|
||||
The function is purely an assertion; it performs no transformation of the data and has no effect on correct input.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The sequence that must contain exactly one item. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()` — the single item from the sequence, unchanged. Raises `FORG0005` if the sequence does not contain exactly one item.
|
||||
|
||||
## Examples
|
||||
|
||||
### Asserting a unique key lookup
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<employees>
|
||||
<employee id="E001"><name>Alice</name></employee>
|
||||
<employee id="E002"><name>Bob</name></employee>
|
||||
</employees>
|
||||
```
|
||||
|
||||
**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="/employees">
|
||||
<result>
|
||||
<xsl:variable name="emp" select="exactly-one(employee[@id='E001'])"/>
|
||||
<found><xsl:value-of select="$emp/name"/></found>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<found>Alice</found>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Catching the error with try/catch (XSLT 3.0)
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:err="http://www.w3.org/2005/xqt-errors">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/employees">
|
||||
<result>
|
||||
<xsl:try>
|
||||
<xsl:variable name="emp" select="exactly-one(employee[@id='UNKNOWN'])"/>
|
||||
<found><xsl:value-of select="$emp/name"/></found>
|
||||
<xsl:catch errors="*">
|
||||
<error>No unique employee found: <xsl:value-of select="$err:description"/></error>
|
||||
</xsl:catch>
|
||||
</xsl:try>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<error>No unique employee found: ...</error>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The error code raised is `err:FORG0005` defined in the XPath/XQuery Functions and Operators specification.
|
||||
- `exactly-one()` is equivalent to writing `$seq[1][last() = 1]` as a guard, but is cleaner and raises a standard error code.
|
||||
- In XSLT 2.0 function signatures, the `item()` return type implicitly asserts exactly one item; `exactly-one()` makes that same assertion in an expression context.
|
||||
- For sequences that may be empty, use `zero-or-one()` instead; for sequences that must be non-empty, use `one-or-more()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [zero-or-one()](../xpath-zero-or-one)
|
||||
- [one-or-more()](../xpath-one-or-more)
|
||||
- [error()](../xpath-error)
|
||||
- [deep-equal()](../xpath-deep-equal)
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: "exists()"
|
||||
description: "Returns true if the sequence contains at least one item, and false if it is empty."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "sequence function"
|
||||
syntax: "exists(sequence)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`exists()` tests whether a sequence is non-empty. It returns `true` as soon as it finds at least one item, making it potentially more efficient than `count($seq) gt 0` because it can stop evaluation early. It is the complement of `empty()`.
|
||||
|
||||
While XSLT 1.0 used boolean coercion of node sets (e.g., `if ($nodes)`) to test for existence, `exists()` is the explicit and type-safe XPath 2.0 way to do the same.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The sequence to test. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the sequence contains one or more items, `false` if it is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Conditional output based on element existence
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<section id="intro">
|
||||
<title>Introduction</title>
|
||||
<content>Some text here.</content>
|
||||
<footnotes>
|
||||
<fn>Source: Wikipedia</fn>
|
||||
</footnotes>
|
||||
</section>
|
||||
<section id="body">
|
||||
<title>Main Content</title>
|
||||
<content>Body text.</content>
|
||||
</section>
|
||||
</report>
|
||||
```
|
||||
|
||||
**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="html" indent="yes"/>
|
||||
|
||||
<xsl:template match="/report">
|
||||
<html><body>
|
||||
<xsl:apply-templates select="section"/>
|
||||
</body></html>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="section">
|
||||
<section>
|
||||
<h2><xsl:value-of select="title"/></h2>
|
||||
<p><xsl:value-of select="content"/></p>
|
||||
<xsl:if test="exists(footnotes/fn)">
|
||||
<aside>
|
||||
<xsl:for-each select="footnotes/fn">
|
||||
<p class="fn"><xsl:value-of select="."/></p>
|
||||
</xsl:for-each>
|
||||
</aside>
|
||||
</xsl:if>
|
||||
</section>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:** The intro section renders an `<aside>` with footnotes; the body section does not.
|
||||
|
||||
### Checking whether a variable holds a result
|
||||
|
||||
**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="/inventory">
|
||||
<xsl:variable name="out-of-stock" select="item[@qty = 0]"/>
|
||||
<xsl:if test="exists($out-of-stock)">
|
||||
<alert>
|
||||
<xsl:value-of select="count($out-of-stock)"/> item(s) out of stock.
|
||||
</alert>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `exists($seq)` is equivalent to `count($seq) gt 0` but preferred for readability and potential performance benefits.
|
||||
- In XPath 1.0, existence was tested by relying on the boolean value of a node-set: `if ($nodes)`. In XPath 2.0, `exists()` makes the intent explicit and works correctly for all sequence types.
|
||||
- Do not confuse `exists()` with `not(empty($seq))` — they are logically identical, but `exists()` is more readable.
|
||||
- For constraining cardinality rather than just testing, see `zero-or-one()`, `one-or-more()`, and `exactly-one()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [empty()](../xpath-empty)
|
||||
- [count()](../xpath-count)
|
||||
- [one-or-more()](../xpath-one-or-more)
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: "false()"
|
||||
description: "Returns the boolean value false. Used in XPath expressions where an explicit boolean false literal is required."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "boolean function"
|
||||
syntax: "false()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`false()` returns the boolean literal `false`. Like `true()`, it exists because XPath 1.0 has no bare boolean keyword syntax — the word `false` alone in an expression would be interpreted as an element name or QName, not as a boolean constant.
|
||||
|
||||
Practical uses include: initialising boolean variables to a known `false` state, writing conditions that are intentionally disabled during development, and comparing the result of boolean expressions against a known `false` value.
|
||||
|
||||
In most production stylesheets, `false()` appears less often than `true()` because conditions in `xsl:if` and predicates are already negated with `not()`, but it is occasionally needed in parameter defaults or variable declarations.
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — always returns `false`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Disable a branch during development
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<title>Annual Report</title>
|
||||
<section>Introduction</section>
|
||||
</report>
|
||||
```
|
||||
|
||||
**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:variable name="debugMode" select="false()"/>
|
||||
|
||||
<xsl:template match="/report">
|
||||
<output>
|
||||
<xsl:if test="$debugMode">
|
||||
<debug>Debug output here</debug>
|
||||
</xsl:if>
|
||||
<title><xsl:value-of select="title"/></title>
|
||||
<xsl:for-each select="section">
|
||||
<section><xsl:value-of select="."/></section>
|
||||
</xsl:for-each>
|
||||
</output>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<output>
|
||||
<title>Annual Report</title>
|
||||
<section>Introduction</section>
|
||||
</output>
|
||||
```
|
||||
|
||||
### Compare the result of a boolean expression
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings>
|
||||
<feature name="export" enabled="no"/>
|
||||
<feature name="import" enabled="yes"/>
|
||||
</settings>
|
||||
```
|
||||
|
||||
**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="/settings">
|
||||
<status>
|
||||
<xsl:for-each select="feature">
|
||||
<xsl:variable name="active" select="@enabled = 'yes'"/>
|
||||
<feature name="{@name}" active="{$active}">
|
||||
<xsl:if test="$active = false()">
|
||||
<note>This feature is off.</note>
|
||||
</xsl:if>
|
||||
</feature>
|
||||
</xsl:for-each>
|
||||
</status>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<status>
|
||||
<feature name="export" active="false">
|
||||
<note>This feature is off.</note>
|
||||
</feature>
|
||||
<feature name="import" active="true"/>
|
||||
</status>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- XPath 1.0 has no bare boolean literals; `false()` and `true()` are the canonical way to represent boolean constants.
|
||||
- `$var = false()` is equivalent to `not($var)` when `$var` holds a boolean, but the intent can be clearer with the explicit comparison.
|
||||
- When outputting `false()` via `xsl:value-of`, the result is the string `"false"`, not the empty string.
|
||||
- In XSLT 2.0+ the function is unchanged; it remains a zero-argument function returning `xs:boolean`.
|
||||
|
||||
## See also
|
||||
|
||||
- [true()](../xpath-true)
|
||||
- [boolean()](../xpath-boolean)
|
||||
- [not()](../xpath-not)
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "filter()"
|
||||
description: "Returns items from a sequence for which a predicate function returns true, discarding all others."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "filter(sequence, predicate)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`filter()` applies a predicate function to each item in a sequence and returns only those items for which the predicate returns `true`. It is the functional equivalent of an XPath predicate expression but accepts a function item, enabling reusable and composable filtering logic.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The sequence to filter. |
|
||||
| `predicate` | function(item()) as xs:boolean | Yes | A function of arity 1 that returns true to keep the item, false to discard it. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the subsequence of items for which the predicate returned `true`, in document order.
|
||||
|
||||
## Examples
|
||||
|
||||
### Filtering even numbers
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<result>
|
||||
<xsl:variable name="numbers" select="1 to 10"/>
|
||||
<xsl:variable name="evens" select="filter($numbers, function($n) { $n mod 2 = 0 })"/>
|
||||
<xsl:for-each select="$evens">
|
||||
<num><xsl:value-of select="."/></num>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<num>2</num>
|
||||
<num>4</num>
|
||||
<num>6</num>
|
||||
<num>8</num>
|
||||
<num>10</num>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Filtering XML nodes by attribute value
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<orders>
|
||||
<order id="1" status="shipped" amount="99.00"/>
|
||||
<order id="2" status="pending" amount="45.00"/>
|
||||
<order id="3" status="shipped" amount="120.00"/>
|
||||
<order id="4" status="cancelled" amount="30.00"/>
|
||||
</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:variable name="shipped"
|
||||
select="filter(order, function($o) { $o/@status = 'shipped' })"/>
|
||||
<shipped-orders total="{sum($shipped/@amount)}">
|
||||
<xsl:copy-of select="$shipped"/>
|
||||
</shipped-orders>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<shipped-orders total="219">
|
||||
<order id="1" status="shipped" amount="99.00"/>
|
||||
<order id="3" status="shipped" amount="120.00"/>
|
||||
</shipped-orders>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The predicate function must return `xs:boolean`; effective boolean value (EBV) is not applied automatically.
|
||||
- `filter()` preserves the original sequence order.
|
||||
- Composable with `for-each()`, `fold-left()`, and `sort()` for pipeline-style data transformation.
|
||||
- For arrays, use `array:filter()` which operates on array members rather than a flat sequence.
|
||||
|
||||
## See also
|
||||
|
||||
- [for-each()](../xpath-for-each)
|
||||
- [fold-left()](../xpath-fold-left)
|
||||
- [fold-right()](../xpath-fold-right)
|
||||
- [for-each-pair()](../xpath-for-each-pair)
|
||||
- [array:filter()](../xpath-array-filter)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: "floor()"
|
||||
description: "Returns the largest integer not greater than the argument — equivalent to rounding a number down toward negative infinity."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "numeric function"
|
||||
syntax: "floor(number)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`floor()` returns the largest integer that is less than or equal to its argument. In plain terms, it rounds a number **down** toward negative infinity. For positive numbers this truncates the decimal part; for negative numbers this rounds away from zero.
|
||||
|
||||
The argument is first converted to a number using the same rules as `number()`. If the argument is already an integer, it is returned unchanged. If the argument is `NaN` or infinite, the same special value is returned.
|
||||
|
||||
Common uses include computing page numbers, calculating array indices from fractional results, and trimming calculated dimensions to integer pixel values.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `number` | xs:double | Yes | The number to round down. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:double` — the largest integer value less than or equal to the argument.
|
||||
|
||||
## Examples
|
||||
|
||||
### Compute page count from item count
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<catalog>
|
||||
<item>A</item>
|
||||
<item>B</item>
|
||||
<item>C</item>
|
||||
<item>D</item>
|
||||
<item>E</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:variable name="pageSize" select="2"/>
|
||||
|
||||
<xsl:template match="/catalog">
|
||||
<xsl:variable name="total" select="count(item)"/>
|
||||
<pagination>
|
||||
<total-items><xsl:value-of select="$total"/></total-items>
|
||||
<full-pages><xsl:value-of select="floor($total div $pageSize)"/></full-pages>
|
||||
</pagination>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<pagination>
|
||||
<total-items>5</total-items>
|
||||
<full-pages>2</full-pages>
|
||||
</pagination>
|
||||
```
|
||||
|
||||
### Floor of positive and negative numbers
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<values>
|
||||
<v>3.7</v>
|
||||
<v>-3.7</v>
|
||||
<v>5.0</v>
|
||||
</values>
|
||||
```
|
||||
|
||||
**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="/values">
|
||||
<results>
|
||||
<xsl:for-each select="v">
|
||||
<floor of="{.}"><xsl:value-of select="floor(.)"/></floor>
|
||||
</xsl:for-each>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<floor of="3.7">3</floor>
|
||||
<floor of="-3.7">-4</floor>
|
||||
<floor of="5.0">5</floor>
|
||||
</results>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `floor(-3.7)` returns `-4`, not `-3`. Rounding is always toward negative infinity, not toward zero.
|
||||
- If the argument is `NaN`, `floor()` returns `NaN`.
|
||||
- If the argument is `Infinity` or `-Infinity`, the same infinity is returned unchanged.
|
||||
- `floor()` returns a `double` type in XPath 1.0, so the output may include a trailing `.0` on some processors when serialised. Use `round()` or integer arithmetic if you need a guaranteed integer format.
|
||||
- For rounding toward zero (truncation), there is no dedicated XPath 1.0 function; the common workaround is `floor($n)` for positive numbers or `ceiling($n)` for negative ones.
|
||||
|
||||
## See also
|
||||
|
||||
- [ceiling()](../xpath-ceiling)
|
||||
- [round()](../xpath-round)
|
||||
- [number()](../xpath-number)
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: "fold-left()"
|
||||
description: "Accumulates a result by applying a function left-to-right over a sequence, starting from an initial zero value."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "fold-left(sequence, zero, function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`fold-left()` (also called a left reduce) processes a sequence from left to right. It begins with an initial accumulator value (`zero`) and repeatedly applies a binary function that takes the current accumulator and the next item, producing the new accumulator. The final accumulator value is the result.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The sequence to fold over. |
|
||||
| `zero` | item()* | Yes | The initial accumulator value. |
|
||||
| `function` | function(item()*, item()) as item()* | Yes | A binary function: (accumulator, currentItem) → newAccumulator. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the final accumulated value after processing all items.
|
||||
|
||||
## Examples
|
||||
|
||||
### Summing a sequence of numbers
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<result>
|
||||
<xsl:variable name="nums" select="(1, 2, 3, 4, 5)"/>
|
||||
<sum>
|
||||
<xsl:value-of select="fold-left($nums, 0, function($acc, $x) { $acc + $x })"/>
|
||||
</sum>
|
||||
<product>
|
||||
<xsl:value-of select="fold-left($nums, 1, function($acc, $x) { $acc * $x })"/>
|
||||
</product>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<sum>15</sum>
|
||||
<product>120</product>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Building a string from a sequence
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tags>
|
||||
<tag>xslt</tag>
|
||||
<tag>xpath</tag>
|
||||
<tag>xml</tag>
|
||||
</tags>
|
||||
```
|
||||
|
||||
**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="/tags">
|
||||
<result>
|
||||
<xsl:value-of select="fold-left(
|
||||
tag[position() gt 1],
|
||||
string(tag[1]),
|
||||
function($acc, $t) { $acc || ', ' || string($t) }
|
||||
)"/>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>xslt, xpath, xml</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `fold-left()` processes items in sequence order (left to right). For right-to-left, use `fold-right()`.
|
||||
- If the sequence is empty, the `zero` value is returned unchanged.
|
||||
- The accumulator can be any XDM value, including maps, arrays, or sequences.
|
||||
- For array-based folding, use `array:fold-left()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [fold-right()](../xpath-fold-right)
|
||||
- [for-each()](../xpath-for-each)
|
||||
- [filter()](../xpath-filter)
|
||||
- [for-each-pair()](../xpath-for-each-pair)
|
||||
- [array:fold-left()](../xpath-array-fold-left)
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: "fold-right()"
|
||||
description: "Accumulates a result by applying a function right-to-left over a sequence, starting from an initial zero value."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "fold-right(sequence, zero, function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`fold-right()` (also called a right reduce) processes a sequence from right to left. It begins with an initial accumulator value (`zero`) and repeatedly applies a binary function that combines the current item with the accumulated result. This produces different results from `fold-left()` for non-associative operations.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The sequence to fold over. |
|
||||
| `zero` | item()* | Yes | The initial accumulator value (rightmost identity). |
|
||||
| `function` | function(item(), item()*) as item()* | Yes | A binary function: (currentItem, accumulator) → newAccumulator. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the final accumulated value after processing all items from right to left.
|
||||
|
||||
## Examples
|
||||
|
||||
### Right-fold to build a nested structure
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="text"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<!-- fold-right builds: cons(1, cons(2, cons(3, nil))) -->
|
||||
<xsl:variable name="items" select="(1, 2, 3)"/>
|
||||
<xsl:value-of select="fold-right($items, 'nil',
|
||||
function($item, $acc) { 'cons(' || $item || ', ' || $acc || ')' }
|
||||
)"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
cons(1, cons(2, cons(3, nil)))
|
||||
```
|
||||
|
||||
### Reversing a sequence with fold-right
|
||||
|
||||
**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="/">
|
||||
<xsl:variable name="items" select="('a', 'b', 'c', 'd')"/>
|
||||
<xsl:variable name="reversed" select="
|
||||
fold-right($items, (),
|
||||
function($item, $acc) { ($acc, $item) }
|
||||
)"/>
|
||||
<result>
|
||||
<xsl:for-each select="$reversed">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<item>d</item>
|
||||
<item>c</item>
|
||||
<item>b</item>
|
||||
<item>a</item>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The function signature for `fold-right()` is `f(item, accumulator)` — note the argument order is reversed compared to `fold-left()`.
|
||||
- For commutative operations (sum, product), `fold-left()` and `fold-right()` produce identical results.
|
||||
- If the sequence is empty, the `zero` value is returned unchanged.
|
||||
- For array-based right folding, use `array:fold-right()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [fold-left()](../xpath-fold-left)
|
||||
- [for-each()](../xpath-for-each)
|
||||
- [filter()](../xpath-filter)
|
||||
- [for-each-pair()](../xpath-for-each-pair)
|
||||
- [array:fold-right()](../xpath-array-fold-right)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: "for-each-pair()"
|
||||
description: "Applies a binary function to corresponding items from two sequences, returning the concatenated results."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "for-each-pair(seq1, seq2, function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`for-each-pair()` simultaneously iterates over two sequences, applying a binary function to each pair of corresponding items (first item from seq1 with first from seq2, second with second, etc.). Processing stops when the shorter sequence is exhausted.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `seq1` | item()* | Yes | The first sequence. |
|
||||
| `seq2` | item()* | Yes | The second sequence. |
|
||||
| `function` | function(item(), item()) as item()* | Yes | A binary function applied to each item pair. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — concatenated results of applying the function to each pair; length equals `min(count(seq1), count(seq2))`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Zipping two sequences into key-value pairs
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<xsl:variable name="keys" select="('name', 'age', 'city')"/>
|
||||
<xsl:variable name="values" select="('Alice', '30', 'Paris')"/>
|
||||
<record>
|
||||
<xsl:sequence select="for-each-pair($keys, $values,
|
||||
function($k, $v) { element {$k} {$v} }
|
||||
)"/>
|
||||
</record>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<record>
|
||||
<name>Alice</name>
|
||||
<age>30</age>
|
||||
<city>Paris</city>
|
||||
</record>
|
||||
```
|
||||
|
||||
### Computing pairwise differences
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data>
|
||||
<actual>10 20 35 50</actual>
|
||||
<expected>12 18 35 48</expected>
|
||||
</data>
|
||||
```
|
||||
|
||||
**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="/data">
|
||||
<xsl:variable name="actual" select="for-each(tokenize(actual), xs:integer#1)"/>
|
||||
<xsl:variable name="expected" select="for-each(tokenize(expected), xs:integer#1)"/>
|
||||
<diffs>
|
||||
<xsl:for-each select="for-each-pair($actual, $expected,
|
||||
function($a, $e) { $a - $e })">
|
||||
<diff><xsl:value-of select="."/></diff>
|
||||
</xsl:for-each>
|
||||
</diffs>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<diffs>
|
||||
<diff>-2</diff>
|
||||
<diff>2</diff>
|
||||
<diff>0</diff>
|
||||
<diff>2</diff>
|
||||
</diffs>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- When sequences have different lengths, the result length equals the shorter sequence — excess items from the longer sequence are ignored.
|
||||
- The function must accept exactly two arguments.
|
||||
- For array-based pair processing, use `array:for-each-pair()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [for-each()](../xpath-for-each)
|
||||
- [filter()](../xpath-filter)
|
||||
- [fold-left()](../xpath-fold-left)
|
||||
- [fold-right()](../xpath-fold-right)
|
||||
- [array:for-each-pair()](../xpath-array-for-each-pair)
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: "for-each()"
|
||||
description: "Applies a function to each item of a sequence and returns the concatenation of all results."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "for-each(sequence, function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`for-each()` iterates over a sequence and applies a unary function to each item, returning a new sequence that is the concatenation of all individual results. It is the functional equivalent of `xsl:for-each` but operates as an XPath expression, making it composable with other higher-order functions.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The sequence of items to iterate over. |
|
||||
| `function` | function(item()) as item()* | Yes | A function of arity 1 applied to each item. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the concatenated results of applying the function to each item.
|
||||
|
||||
## Examples
|
||||
|
||||
### Converting a sequence of strings to upper case
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<result>
|
||||
<xsl:variable name="words" select="('apple', 'banana', 'cherry')"/>
|
||||
<xsl:variable name="upper" select="for-each($words, upper-case#1)"/>
|
||||
<xsl:for-each select="$upper">
|
||||
<word><xsl:value-of select="."/></word>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<word>APPLE</word>
|
||||
<word>BANANA</word>
|
||||
<word>CHERRY</word>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Extracting attributes from nodes using for-each()
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<products>
|
||||
<product id="p1" price="10.00"/>
|
||||
<product id="p2" price="25.50"/>
|
||||
<product id="p3" price="5.99"/>
|
||||
</products>
|
||||
```
|
||||
|
||||
**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="/products">
|
||||
<xsl:variable name="prices"
|
||||
select="for-each(product, function($p) { xs:decimal($p/@price) })"/>
|
||||
<summary>
|
||||
<total><xsl:value-of select="sum($prices)"/></total>
|
||||
<max><xsl:value-of select="max($prices)"/></max>
|
||||
</summary>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<summary>
|
||||
<total>41.49</total>
|
||||
<max>25.50</max>
|
||||
</summary>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `for-each()` is an XPath function and must not be confused with the `xsl:for-each` instruction.
|
||||
- The function must accept exactly one argument.
|
||||
- Results from each invocation are concatenated into a flat sequence; use `array:for-each()` if you need to preserve array structure.
|
||||
- Composable with `filter()`, `fold-left()`, and `sort()` for pipeline-style processing.
|
||||
|
||||
## See also
|
||||
|
||||
- [filter()](../xpath-filter)
|
||||
- [fold-left()](../xpath-fold-left)
|
||||
- [fold-right()](../xpath-fold-right)
|
||||
- [for-each-pair()](../xpath-for-each-pair)
|
||||
- [array:for-each()](../xpath-array-for-each)
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
title: "format-dateTime()"
|
||||
description: "Formats an xs:dateTime value into a human-readable string using a picture pattern, with optional locale and calendar support."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "format-dateTime(dateTime, picture, language?, calendar?, place?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`format-dateTime()` converts an `xs:dateTime` value into a formatted string using the picture pattern syntax shared by `format-date()` and `format-time()`. It supports all date and time component specifiers in a single call.
|
||||
|
||||
Common specifiers:
|
||||
|
||||
| Specifier | Meaning |
|
||||
|-----------|---------|
|
||||
| `[Y]` | Year (4 digits by default) |
|
||||
| `[M]` | Month as a number |
|
||||
| `[MNn]` | Month name (e.g., "April") |
|
||||
| `[D]` | Day of the month |
|
||||
| `[H]` | Hour, 24-hour clock (0–23) |
|
||||
| `[h]` | Hour, 12-hour clock (1–12) |
|
||||
| `[m]` | Minute |
|
||||
| `[s]` | Second |
|
||||
| `[P]` | AM/PM marker |
|
||||
| `[Z]` | Timezone offset |
|
||||
|
||||
Width modifiers (e.g., `[D01]`, `[m01]`) control zero-padding.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `dateTime` | xs:dateTime? | Yes | The dateTime value to format. Returns an empty string for the empty sequence. |
|
||||
| `picture` | xs:string | Yes | The picture pattern controlling the output format. |
|
||||
| `language` | xs:string? | No | BCP 47 language tag (e.g., `"en"`, `"fr"`). |
|
||||
| `calendar` | xs:string? | No | Calendar system identifier. Implementation-defined. |
|
||||
| `place` | xs:string? | No | Place or timezone identifier. Implementation-defined. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the formatted date-time string, or an empty string if `dateTime` is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Format an event timestamp
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<events>
|
||||
<event timestamp="2026-04-18T09:30:00">Morning session</event>
|
||||
<event timestamp="2026-04-18T14:00:00">Afternoon 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"
|
||||
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 display="{format-dateTime(xs:dateTime(@timestamp), '[D] [MNn] [Y] at [H01]:[m01]')}">
|
||||
<xsl:value-of select="."/>
|
||||
</event>
|
||||
</xsl:for-each>
|
||||
</events>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<events>
|
||||
<event display="18 April 2026 at 09:30">Morning session</event>
|
||||
<event display="18 April 2026 at 14:00">Afternoon workshop</event>
|
||||
</events>
|
||||
```
|
||||
|
||||
### Embed a generation timestamp in a report
|
||||
|
||||
**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="/">
|
||||
<report generated="{format-dateTime(current-dateTime(), '[Y]-[M01]-[D01]T[H01]:[m01]:[s01]')}">
|
||||
<xsl:apply-templates/>
|
||||
</report>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```xml
|
||||
<report generated="2026-04-18T14:32:07">
|
||||
...
|
||||
</report>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The input must be `xs:dateTime`, not a plain string. Cast attribute values with `xs:dateTime(@attr)`.
|
||||
- Picture syntax follows the XPath 2.0 specification, not Java or POSIX conventions.
|
||||
- To format only the date or time portion of a `xs:dateTime`, cast first: `format-date(xs:date(current-dateTime()), ...)`.
|
||||
|
||||
## See also
|
||||
|
||||
- [format-date()](../xpath-format-date)
|
||||
- [format-time()](../xpath-format-time)
|
||||
- [current-dateTime()](../xpath-current-date-time)
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
title: "format-number()"
|
||||
description: "Formats a number as a string using a picture pattern and an optional named decimal format, following the same rules as Java's DecimalFormat."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "numeric function"
|
||||
syntax: "format-number(number, pattern, decimal-format-name?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`format-number()` converts a number to a formatted string using a picture pattern string and optional named `xsl:decimal-format` settings. The pattern language follows the same conventions as Java's `java.text.DecimalFormat` class.
|
||||
|
||||
The pattern is composed of two optional sub-patterns separated by a semicolon: the **positive pattern** and the **negative pattern**. If only one sub-pattern is given it applies to both positive and negative numbers (with a minus sign prepended for negatives).
|
||||
|
||||
Common pattern characters:
|
||||
- `0` — mandatory digit position (outputs a zero if no digit is present).
|
||||
- `#` — optional digit position (omitted if not significant).
|
||||
- `.` — decimal separator.
|
||||
- `,` — grouping separator (thousands separator).
|
||||
- `%` — multiplies by 100 and appends a percent sign.
|
||||
- `E` — separates mantissa and exponent in scientific notation.
|
||||
|
||||
The optional third argument names an `xsl:decimal-format` element that can customise the separator characters, infinity string, NaN string, and other locale-specific settings.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `number` | xs:double | Yes | The number to format. |
|
||||
| `pattern` | xs:string | Yes | The picture pattern string. |
|
||||
| `decimal-format-name` | xs:QName | No | Name of an `xsl:decimal-format` to use for locale-specific symbols. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the formatted number as a string.
|
||||
|
||||
## Examples
|
||||
|
||||
### Format currency and percentages
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report>
|
||||
<revenue>125678.9</revenue>
|
||||
<growth>0.0735</growth>
|
||||
</report>
|
||||
```
|
||||
|
||||
**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="/report">
|
||||
<formatted>
|
||||
<revenue><xsl:value-of select="format-number(revenue, '$#,##0.00')"/></revenue>
|
||||
<growth><xsl:value-of select="format-number(growth, '0.00%')"/></growth>
|
||||
</formatted>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<formatted>
|
||||
<revenue>$125,678.90</revenue>
|
||||
<growth>7.35%</growth>
|
||||
</formatted>
|
||||
```
|
||||
|
||||
### Use a named decimal format for European locale
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<prices>
|
||||
<price>1234.56</price>
|
||||
<price>0.5</price>
|
||||
</prices>
|
||||
```
|
||||
|
||||
**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:decimal-format name="european"
|
||||
decimal-separator=","
|
||||
grouping-separator="."
|
||||
NaN="n/a"
|
||||
infinity="inf"/>
|
||||
|
||||
<xsl:template match="/prices">
|
||||
<formatted>
|
||||
<xsl:for-each select="price">
|
||||
<price><xsl:value-of select="format-number(., '#.##0,00', 'european')"/></price>
|
||||
</xsl:for-each>
|
||||
</formatted>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<formatted>
|
||||
<price>1.234,56</price>
|
||||
<price>0,50</price>
|
||||
</formatted>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `format-number(NaN, '0')` returns the NaN string defined by the `xsl:decimal-format` (default is `"NaN"`).
|
||||
- `format-number(number('abc'), '#')` also returns `"NaN"` because `number('abc')` is `NaN`.
|
||||
- The `%` pattern character multiplies by 100 before formatting; `‰` (per-mille) multiplies by 1000.
|
||||
- Negative numbers use the negative sub-pattern if provided; otherwise they use the positive pattern with a leading minus sign (using the minus sign character of the decimal format).
|
||||
- In XSLT 2.0+, `format-number()` is still available but the pattern language is enhanced and the function integrates with `xsl:decimal-format` improvements.
|
||||
|
||||
## See also
|
||||
|
||||
- [number()](../xpath-number)
|
||||
- [round()](../xpath-round)
|
||||
- [xsl:decimal-format](../xsl-decimal-format)
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: "format-time()"
|
||||
description: "Formats an xs:time value into a human-readable string using a picture pattern, with optional locale and calendar support."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "format-time(time, picture, language?, calendar?, place?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`format-time()` converts an `xs:time` value into a formatted string using the same **picture pattern** syntax used by `format-date()` and `format-dateTime()`. Picture components are enclosed in square brackets.
|
||||
|
||||
Common time specifiers:
|
||||
|
||||
| Specifier | Meaning |
|
||||
|-----------|---------|
|
||||
| `[H]` | Hour, 24-hour clock (0–23) |
|
||||
| `[h]` | Hour, 12-hour clock (1–12) |
|
||||
| `[m]` | Minute (0–59) |
|
||||
| `[s]` | Second (0–59) |
|
||||
| `[f]` | Fractional seconds |
|
||||
| `[P]` | AM/PM marker |
|
||||
|
||||
Width modifiers like `[H01]` add zero-padding (e.g., `07` instead of `7`).
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `time` | xs:time? | Yes | The time value to format. Returns an empty string for the empty sequence. |
|
||||
| `picture` | xs:string | Yes | The picture pattern controlling the output format. |
|
||||
| `language` | xs:string? | No | BCP 47 language tag (e.g., `"en"`, `"fr"`). |
|
||||
| `calendar` | xs:string? | No | Calendar system identifier. Implementation-defined. |
|
||||
| `place` | xs:string? | No | Place or timezone identifier. Implementation-defined. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the formatted time string, or an empty string if `time` is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Format appointment times
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schedule>
|
||||
<appointment time="09:30:00">Team standup</appointment>
|
||||
<appointment time="14:00:00">Client call</appointment>
|
||||
</schedule>
|
||||
```
|
||||
|
||||
**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="/schedule">
|
||||
<schedule>
|
||||
<xsl:for-each select="appointment">
|
||||
<appointment display="{format-time(xs:time(@time), '[h]:[m01] [P]')}">
|
||||
<xsl:value-of select="."/>
|
||||
</appointment>
|
||||
</xsl:for-each>
|
||||
</schedule>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<schedule>
|
||||
<appointment display="9:30 am">Team standup</appointment>
|
||||
<appointment display="2:00 pm">Client call</appointment>
|
||||
</schedule>
|
||||
```
|
||||
|
||||
### Format the current time as HH:MM:SS
|
||||
|
||||
**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-time(current-time(), '[H01]:[m01]:[s01]')"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```
|
||||
14:32:07
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The input must be an `xs:time` value, not a plain string. Cast with `xs:time(@attr)`.
|
||||
- Picture syntax is specific to XPath 2.0 and differs from Java `SimpleDateFormat` or POSIX `strftime`.
|
||||
- Language support for AM/PM markers and other named components varies by processor.
|
||||
|
||||
## See also
|
||||
|
||||
- [format-date()](../xpath-format-date)
|
||||
- [format-dateTime()](../xpath-format-date-time)
|
||||
- [current-time()](../xpath-current-time)
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: "function-arity()"
|
||||
description: "Returns the number of arguments (arity) that a function item accepts."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "function-arity(function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`function-arity()` returns the arity — the number of parameters — of a function item. This is useful when working with higher-order functions to validate that a function accepts the expected number of arguments before calling it, or when building generic utilities that inspect function items.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `function` | function(*) | Yes | The function item whose arity is to be returned. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer` — the number of parameters the function accepts.
|
||||
|
||||
## Examples
|
||||
|
||||
### Checking arity before apply()
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<result>
|
||||
<xsl:variable name="fn" select="upper-case#1"/>
|
||||
<arity><xsl:value-of select="function-arity($fn)"/></arity>
|
||||
<xsl:if test="function-arity($fn) = 1">
|
||||
<output><xsl:value-of select="apply($fn, ['hello'])"/></output>
|
||||
</xsl:if>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<arity>1</arity>
|
||||
<output>HELLO</output>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Introspecting a list of functions
|
||||
|
||||
**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="/">
|
||||
<xsl:variable name="fns" select="(
|
||||
upper-case#1,
|
||||
substring#2,
|
||||
substring#3,
|
||||
function($a, $b) { $a + $b }
|
||||
)"/>
|
||||
<functions>
|
||||
<xsl:for-each select="$fns">
|
||||
<fn>
|
||||
<name><xsl:value-of select="(function-name(.), 'anonymous')[1]"/></name>
|
||||
<arity><xsl:value-of select="function-arity(.)"/></arity>
|
||||
</fn>
|
||||
</xsl:for-each>
|
||||
</functions>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<functions>
|
||||
<fn><name>fn:upper-case</name><arity>1</arity></fn>
|
||||
<fn><name>fn:substring</name><arity>2</arity></fn>
|
||||
<fn><name>fn:substring</name><arity>3</arity></fn>
|
||||
<fn><name>anonymous</name><arity>2</arity></fn>
|
||||
</functions>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Partial function application (e.g., `substring(?, 1, 3)`) reduces the arity by the number of bound arguments.
|
||||
- `function-arity()` never returns the empty sequence; it always returns a non-negative integer.
|
||||
- A zero-arity function (`function() { ... }`) returns `0`.
|
||||
|
||||
## See also
|
||||
|
||||
- [function-name()](../xpath-function-name)
|
||||
- [function-lookup()](../xpath-function-lookup)
|
||||
- [apply()](../xpath-apply)
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: "function-available()"
|
||||
description: "Returns true if the named function is available in the current XSLT processor, supporting portable use of extension functions."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "function-available(name)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`function-available()` tests whether the named function can be called in the current transformation context and returns a boolean. This includes core XPath functions, XSLT-specific functions (such as `document()`, `key()`, and `format-number()`), and any extension functions provided by the processor or bound via namespace declarations.
|
||||
|
||||
The argument is a string containing the QName of the function. If the QName is in no namespace or the `fn:` namespace, built-in XPath/XSLT functions are tested. If it is in another namespace, vendor or EXSLT extension functions are tested.
|
||||
|
||||
`function-available()` allows stylesheets to be written once and run on multiple processors, branching between native and extension implementations as needed. It is commonly paired with `element-available()` for comprehensive capability detection.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | xs:string | Yes | A QName string naming the function to test. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the function is available and callable, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Test for core and extension functions
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doc><value>3.14</value></doc>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:math="http://exslt.org/math">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/doc">
|
||||
<capabilities>
|
||||
<concat-available>
|
||||
<xsl:value-of select="function-available('concat')"/>
|
||||
</concat-available>
|
||||
<math-sqrt-available>
|
||||
<xsl:value-of select="function-available('math:sqrt')"/>
|
||||
</math-sqrt-available>
|
||||
<nonexistent>
|
||||
<xsl:value-of select="function-available('nonexistent-func')"/>
|
||||
</nonexistent>
|
||||
</capabilities>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (Saxon with EXSLT):**
|
||||
```xml
|
||||
<capabilities>
|
||||
<concat-available>true</concat-available>
|
||||
<math-sqrt-available>true</math-sqrt-available>
|
||||
<nonexistent>false</nonexistent>
|
||||
</capabilities>
|
||||
```
|
||||
|
||||
### Conditional use of an EXSLT function
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<items>
|
||||
<item>3</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</items>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:exsl="http://exslt.org/common">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/items">
|
||||
<result>
|
||||
<xsl:choose>
|
||||
<xsl:when test="function-available('exsl:node-set')">
|
||||
<method>exsl:node-set available</method>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<method>Fallback: no node-set conversion</method>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<xsl:for-each select="item">
|
||||
<value><xsl:value-of select="."/></value>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `function-available()` tests callable functions only — it does not test XSLT instruction elements. Use `element-available()` for that.
|
||||
- The prefix in the QName string must be declared in the stylesheet for namespace-qualified function names; otherwise an error is raised.
|
||||
- All standard XPath 1.0 core functions (`string()`, `number()`, `concat()`, etc.) always return `true` in a conformant processor.
|
||||
- In XSLT 2.0+, `function-available()` remains available. It can optionally take a second argument specifying the arity (number of arguments) of the function to test.
|
||||
|
||||
## See also
|
||||
|
||||
- [element-available()](../xpath-element-available)
|
||||
- [system-property()](../xpath-system-property)
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: "function-lookup()"
|
||||
description: "Returns a function item identified by its QName and arity, or the empty sequence if no such function is available."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "function-lookup(name, arity)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`function-lookup()` looks up a function by its expanded QName and arity (number of parameters) in the static context. If found, it returns the function as a function item; if no such function exists, it returns the empty sequence. This enables optional feature detection and dynamic dispatch patterns.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `name` | xs:QName | Yes | The expanded QName of the function to look up. |
|
||||
| `arity` | xs:integer | Yes | The number of arguments (arity) the function accepts. |
|
||||
|
||||
## Return value
|
||||
|
||||
`function(*)?` — the matching function item, or the empty sequence if not found.
|
||||
|
||||
## Examples
|
||||
|
||||
### Safe lookup before calling
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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"
|
||||
xmlns:math="http://www.w3.org/2005/xpath-functions/math">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<result>
|
||||
<xsl:variable name="sqrt" select="function-lookup(xs:QName('math:sqrt'), 1)"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="exists($sqrt)">
|
||||
<value><xsl:value-of select="$sqrt(16)"/></value>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<value>math:sqrt not available</value>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<value>4</value>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Building a function dispatch table
|
||||
|
||||
**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="/">
|
||||
<xsl:variable name="dispatch" select="map{
|
||||
'upper': function-lookup(xs:QName('upper-case'), 1),
|
||||
'lower': function-lookup(xs:QName('lower-case'), 1),
|
||||
'norm': function-lookup(xs:QName('normalize-space'), 1)
|
||||
}"/>
|
||||
<results>
|
||||
<xsl:for-each select="('upper', 'lower', 'norm')">
|
||||
<xsl:variable name="fn" select="map:get($dispatch, .)"/>
|
||||
<item op="{.}">
|
||||
<xsl:value-of select="if (exists($fn)) then $fn(' Hello World ') else 'N/A'"/>
|
||||
</item>
|
||||
</xsl:for-each>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<item op="upper"> HELLO WORLD </item>
|
||||
<item op="lower"> hello world </item>
|
||||
<item op="norm">Hello World</item>
|
||||
</results>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The `name` argument must be an `xs:QName` created with `xs:QName()` or a namespace-aware constructor.
|
||||
- For built-in XPath functions, the namespace URI is `http://www.w3.org/2005/xpath-functions`.
|
||||
- Returns the empty sequence (not an error) when the function is not found, making it safe for feature detection.
|
||||
- User-defined functions declared with `xsl:function` are also accessible via `function-lookup()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [apply()](../xpath-apply)
|
||||
- [function-name()](../xpath-function-name)
|
||||
- [function-arity()](../xpath-function-arity)
|
||||
- [for-each()](../xpath-for-each)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "function-name()"
|
||||
description: "Returns the QName of a named function item, or the empty sequence if the function is anonymous."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "higher-order function"
|
||||
syntax: "function-name(function)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`function-name()` inspects a function item and returns its QName if the function has a name. For anonymous inline functions (created with `function(...)` expressions), it returns the empty sequence. This is useful for logging, debugging, and dynamic function inspection.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `function` | function(*) | Yes | The function item to inspect. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:QName?` — the QName of the function, or the empty sequence for anonymous functions.
|
||||
|
||||
## Examples
|
||||
|
||||
### Inspecting named and anonymous functions
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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"
|
||||
xmlns:f="http://example.com/fn">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:function name="f:double" as="xs:integer">
|
||||
<xsl:param name="x" as="xs:integer"/>
|
||||
<xsl:sequence select="$x * 2"/>
|
||||
</xsl:function>
|
||||
|
||||
<xsl:template match="/">
|
||||
<result>
|
||||
<named>
|
||||
<xsl:value-of select="function-name(f:double#1)"/>
|
||||
</named>
|
||||
<anonymous>
|
||||
<xsl:variable name="fn" select="function($x) { $x * 2 }"/>
|
||||
<xsl:value-of select="(function-name($fn), 'anonymous')[1]"/>
|
||||
</anonymous>
|
||||
<builtin>
|
||||
<xsl:value-of select="function-name(upper-case#1)"/>
|
||||
</builtin>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<named>f:double</named>
|
||||
<anonymous>anonymous</anonymous>
|
||||
<builtin>fn:upper-case</builtin>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Logging function calls in a dispatch table
|
||||
|
||||
**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="/">
|
||||
<xsl:variable name="fns" select="(upper-case#1, lower-case#1, normalize-space#1)"/>
|
||||
<log>
|
||||
<xsl:for-each select="$fns">
|
||||
<entry>
|
||||
<name><xsl:value-of select="function-name(.)"/></name>
|
||||
<arity><xsl:value-of select="function-arity(.)"/></arity>
|
||||
</entry>
|
||||
</xsl:for-each>
|
||||
</log>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<log>
|
||||
<entry><name>fn:upper-case</name><arity>1</arity></entry>
|
||||
<entry><name>fn:lower-case</name><arity>1</arity></entry>
|
||||
<entry><name>fn:normalize-space</name><arity>1</arity></entry>
|
||||
</log>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Anonymous functions created with inline `function(...)` syntax return the empty sequence.
|
||||
- For built-in functions, the local name is the function name without the `fn:` prefix, but `function-name()` returns the fully expanded QName.
|
||||
- Use `local-name-from-QName()` and `namespace-uri-from-QName()` to decompose the returned QName.
|
||||
|
||||
## See also
|
||||
|
||||
- [function-arity()](../xpath-function-arity)
|
||||
- [function-lookup()](../xpath-function-lookup)
|
||||
- [apply()](../xpath-apply)
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
title: "generate-id()"
|
||||
description: "Returns a unique string identifier for a node, guaranteed to be a valid XML name and stable within a single transformation run."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "generate-id(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`generate-id()` returns a string that uniquely identifies a node within the current transformation. The string is guaranteed to:
|
||||
|
||||
- Be a valid XML `Name` (it can be used as an attribute value or part of an ID).
|
||||
- Be unique: different nodes in the same transformation produce different IDs.
|
||||
- Be consistent: calling `generate-id()` on the same node multiple times within one transformation always returns the same string.
|
||||
|
||||
The generated value is arbitrary and processor-specific. It may change between runs or between different XSLT processors; do not store it in output that must be reproducible.
|
||||
|
||||
When called with no argument, `generate-id()` uses the context node. If the argument is an empty node-set, the empty string `""` is returned.
|
||||
|
||||
Common uses include generating `id`/`href` pairs for internal cross-references in HTML output, implementing the Muenchian grouping technique, and creating unique element names when converting to formats that require them.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node-set | No | The node to identify. Defaults to the context node. If empty, returns `""`. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — a unique, valid XML Name for the node, or `""` for an empty node-set.
|
||||
|
||||
## Examples
|
||||
|
||||
### Generate anchor links in HTML output
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sections>
|
||||
<section><title>Introduction</title><p>Welcome.</p></section>
|
||||
<section><title>Usage</title><p>How to use it.</p></section>
|
||||
</sections>
|
||||
```
|
||||
|
||||
**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="html" indent="yes"/>
|
||||
|
||||
<xsl:template match="/sections">
|
||||
<html><body>
|
||||
<!-- Table of contents -->
|
||||
<ul>
|
||||
<xsl:for-each select="section">
|
||||
<li><a href="#{generate-id()}"><xsl:value-of select="title"/></a></li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
<!-- Content -->
|
||||
<xsl:for-each select="section">
|
||||
<h2 id="{generate-id()}"><xsl:value-of select="title"/></h2>
|
||||
<p><xsl:value-of select="p"/></p>
|
||||
</xsl:for-each>
|
||||
</body></html>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (IDs are processor-generated):**
|
||||
```html
|
||||
<html><body>
|
||||
<ul>
|
||||
<li><a href="#d0e2">Introduction</a></li>
|
||||
<li><a href="#d0e7">Usage</a></li>
|
||||
</ul>
|
||||
<h2 id="d0e2">Introduction</h2>
|
||||
<p>Welcome.</p>
|
||||
<h2 id="d0e7">Usage</h2>
|
||||
<p>How to use it.</p>
|
||||
</body></html>
|
||||
```
|
||||
|
||||
### Muenchian grouping — test node identity
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<items>
|
||||
<item cat="A">One</item>
|
||||
<item cat="B">Two</item>
|
||||
<item cat="A">Three</item>
|
||||
</items>
|
||||
```
|
||||
|
||||
**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="by-cat" match="item" use="@cat"/>
|
||||
|
||||
<xsl:template match="/items">
|
||||
<groups>
|
||||
<xsl:for-each select="item[generate-id() = generate-id(key('by-cat', @cat)[1])]">
|
||||
<group cat="{@cat}">
|
||||
<xsl:value-of select="count(key('by-cat', @cat))"/> items
|
||||
</group>
|
||||
</xsl:for-each>
|
||||
</groups>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<groups>
|
||||
<group cat="A">2 items</group>
|
||||
<group cat="B">1 items</group>
|
||||
</groups>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The generated ID is **not persistent**: it may differ between processors and between runs of the same processor. Do not use it as a stable key in output databases or cross-document references.
|
||||
- `generate-id()` on an empty node-set returns `""`, not an error. Check for this case if the argument might be empty.
|
||||
- Two calls to `generate-id()` on the same node within one transformation always return the same value, which is the property that makes the Muenchian grouping technique work.
|
||||
- In XSLT 2.0+, `generate-id()` remains available and unchanged. The `xsl:for-each-group` instruction is usually a cleaner alternative for grouping tasks.
|
||||
|
||||
## See also
|
||||
|
||||
- [id()](../xpath-id)
|
||||
- [key()](../xpath-key)
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: "has-children()"
|
||||
description: "Returns true if the node has one or more child nodes; defaults to the context node if no argument is supplied."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "has-children(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`has-children()` tests whether a node has at least one child node. A child node may be an element, text node, comment, or processing instruction. Attribute nodes and namespace nodes are not children in the XPath data model, so their presence alone does not cause `has-children()` to return `true`.
|
||||
|
||||
When called without arguments, the function tests the context node. When a node is supplied as an argument, that node is tested. If the argument is the empty sequence, `false` is returned.
|
||||
|
||||
The function is particularly useful in streaming mode where examining all children of a node is expensive or impossible after the streaming pass. `has-children()` can be evaluated during streaming as a simple flag before the children are consumed.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node()? | No | The node to test. Defaults to the context node if omitted. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the node has one or more child nodes, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Distinguishing leaf and branch elements
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tree>
|
||||
<branch>
|
||||
<leaf>A</leaf>
|
||||
<leaf>B</leaf>
|
||||
</branch>
|
||||
<leaf>C</leaf>
|
||||
</tree>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/tree">
|
||||
<classified>
|
||||
<xsl:for-each select="*">
|
||||
<node name="{name()}" type="{if (has-children()) then 'branch' else 'leaf'}"/>
|
||||
</xsl:for-each>
|
||||
</classified>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<classified>
|
||||
<node name="branch" type="branch"/>
|
||||
<node name="leaf" type="leaf"/>
|
||||
</classified>
|
||||
```
|
||||
|
||||
### Using has-children() with a supplied node
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/tree">
|
||||
<xsl:value-of select="has-children(branch)"/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="has-children(leaf)"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
true
|
||||
false
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `has-children()` is equivalent to `exists(child::node())` but may be more efficient when the processor does not need to materialize the child sequence.
|
||||
- In streaming mode (`xsl:stream`), `has-children()` is one of the few node tests that can be applied without consuming the children.
|
||||
- Attribute nodes never have children in the XPath data model, so `has-children(@attr)` always returns `false`.
|
||||
- Document nodes may also be tested; a document with at least one child element returns `true`.
|
||||
|
||||
## See also
|
||||
|
||||
- [innermost()](../xpath-innermost)
|
||||
- [outermost()](../xpath-outermost)
|
||||
- [path()](../xpath-path)
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: "hours-from-time()"
|
||||
description: "Extracts the hours component from an xs:time value as an xs:integer in the range 0–23."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "hours-from-time(time)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`hours-from-time()` returns the hours component of an `xs:time` value as an `xs:integer` between 0 and 23. If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `time` | xs:time? | Yes | The time value from which to extract the hours. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer?` — integer from 0 to 23, or the empty sequence if the argument is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Classify times as morning, afternoon, or evening
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schedule>
|
||||
<appointment time="09:30:00">Team standup</appointment>
|
||||
<appointment time="14:00:00">Client call</appointment>
|
||||
<appointment time="18:30:00">Dinner meeting</appointment>
|
||||
</schedule>
|
||||
```
|
||||
|
||||
**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="/schedule">
|
||||
<schedule>
|
||||
<xsl:for-each select="appointment">
|
||||
<xsl:variable name="h" select="hours-from-time(xs:time(@time))"/>
|
||||
<appointment period="{if ($h lt 12) then 'morning' else if ($h lt 18) then 'afternoon' else 'evening'}">
|
||||
<xsl:value-of select="."/>
|
||||
</appointment>
|
||||
</xsl:for-each>
|
||||
</schedule>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<schedule>
|
||||
<appointment period="morning">Team standup</appointment>
|
||||
<appointment period="afternoon">Client call</appointment>
|
||||
<appointment period="evening">Dinner meeting</appointment>
|
||||
</schedule>
|
||||
```
|
||||
|
||||
### Extract hour from the current time
|
||||
|
||||
**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="concat('Current hour: ', hours-from-time(current-time()))"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example):**
|
||||
```
|
||||
Current hour: 14
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The argument must be typed as `xs:time`. Cast string values with `xs:time(@attr)`.
|
||||
- Returns values in the 24-hour clock range (0–23).
|
||||
- For `xs:dateTime` values, use `hours-from-dateTime()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [minutes-from-time()](../xpath-minutes-from-time)
|
||||
- [seconds-from-time()](../xpath-seconds-from-time)
|
||||
- [current-time()](../xpath-current-time)
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: "id()"
|
||||
description: "Selects elements in the document whose ID attribute value matches the given string or space-separated list of IDs."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "id(string)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`id()` returns a node-set of all elements in the same document as the context node whose **ID-typed attribute** matches one or more ID values provided in the argument.
|
||||
|
||||
The argument may be:
|
||||
- A **string** containing one or more whitespace-separated ID values — each is looked up independently.
|
||||
- A **node-set** — each node is converted to its string value, that string is treated as a whitespace-separated list of IDs, and all matching elements are returned.
|
||||
|
||||
An element participates in ID lookup only if the document has an associated DTD or schema that declares the attribute as type `ID`. Without such a declaration, `id()` will always return an empty node-set, even if an attribute is named `id`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string or node-set | Yes | One or more whitespace-separated ID values to look up. |
|
||||
|
||||
## Return value
|
||||
|
||||
`node-set` — the elements whose ID-typed attribute matches the given values, in document order, with no duplicates.
|
||||
|
||||
## Examples
|
||||
|
||||
### Look up a single element by ID (requires DTD)
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE catalog [
|
||||
<!ELEMENT catalog (product+)>
|
||||
<!ELEMENT product (name)>
|
||||
<!ATTLIST product pid ID #REQUIRED>
|
||||
<!ELEMENT name (#PCDATA)>
|
||||
]>
|
||||
<catalog>
|
||||
<product pid="p1"><name>Widget</name></product>
|
||||
<product pid="p2"><name>Gadget</name></product>
|
||||
<product pid="p3"><name>Doohickey</name></product>
|
||||
</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">
|
||||
<found>
|
||||
<xsl:value-of select="id('p2')/name"/>
|
||||
</found>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<found>Gadget</found>
|
||||
```
|
||||
|
||||
### Look up multiple elements by a space-separated list
|
||||
|
||||
**Input XML (with DTD as above):**
|
||||
|
||||
**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">
|
||||
<selection>
|
||||
<xsl:for-each select="id('p1 p3')">
|
||||
<item><xsl:value-of select="name"/></item>
|
||||
</xsl:for-each>
|
||||
</selection>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<selection>
|
||||
<item>Widget</item>
|
||||
<item>Doohickey</item>
|
||||
</selection>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `id()` only works when the XML document has a DTD that declares the attribute type as `ID`. Without a DTD validation pass, the processor has no way to know which attribute holds the ID.
|
||||
- In practice, many documents use an attribute named `id` or `xml:id` without a DTD. For those, use an XPath predicate such as `//*[@id = 'myId']` or the `key()` function instead.
|
||||
- `xml:id` (defined by the W3C xml:id specification) is automatically treated as an ID-typed attribute by conforming XSLT 2.0+ processors without requiring a DTD.
|
||||
- The result node-set is always in document order and contains no duplicates, even if the same ID appears more than once in the argument string.
|
||||
|
||||
## See also
|
||||
|
||||
- [key()](../xpath-key)
|
||||
- [generate-id()](../xpath-generate-id)
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
title: "implicit-timezone()"
|
||||
description: "Returns the processor's implicit timezone as an xs:dayTimeDuration, used when date/time values have no explicit timezone."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "implicit-timezone()"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`implicit-timezone()` returns the implicit timezone of the XPath evaluation context as an `xs:dayTimeDuration`. This is the timezone assumed when comparing or formatting date/time values that do not carry an explicit timezone component.
|
||||
|
||||
The value is processor-defined but typically reflects the system's local timezone. It is expressed as a positive or negative duration relative to UTC (e.g., `PT1H` for UTC+1, `-PT5H` for UTC-5).
|
||||
|
||||
## Parameters
|
||||
|
||||
This function takes no parameters.
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:dayTimeDuration` — the implicit timezone offset from UTC. The value is always a whole number of minutes.
|
||||
|
||||
## Examples
|
||||
|
||||
### Display the implicit timezone
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<context>
|
||||
<implicit-timezone><xsl:value-of select="implicit-timezone()"/></implicit-timezone>
|
||||
</context>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output (example for UTC+1):**
|
||||
```xml
|
||||
<context>
|
||||
<implicit-timezone>PT1H</implicit-timezone>
|
||||
</context>
|
||||
```
|
||||
|
||||
### Normalize a timezone-free date to UTC
|
||||
|
||||
**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">
|
||||
<!-- adjust-dateTime-to-timezone moves the value to UTC (xs:dayTimeDuration('PT0S')) -->
|
||||
<event utc="{adjust-dateTime-to-timezone(xs:dateTime(@timestamp), xs:dayTimeDuration('PT0S'))}">
|
||||
<xsl:value-of select="."/>
|
||||
</event>
|
||||
</xsl:for-each>
|
||||
</events>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `implicit-timezone()` is used internally by the processor when comparing date/time values that lack explicit timezone information.
|
||||
- To retrieve the current date/time with the implicit timezone already applied, use `current-date()`, `current-time()`, or `current-dateTime()`.
|
||||
- To convert values to a specific timezone, use the `adjust-date-to-timezone()`, `adjust-time-to-timezone()`, or `adjust-dateTime-to-timezone()` functions.
|
||||
- The implicit timezone can be set programmatically in Saxon via the `Configuration` API, but is typically the JVM's default timezone.
|
||||
|
||||
## See also
|
||||
|
||||
- [current-date()](../xpath-current-date)
|
||||
- [current-time()](../xpath-current-time)
|
||||
- [current-dateTime()](../xpath-current-date-time)
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "index-of()"
|
||||
description: "Returns a sequence of 1-based integer positions where a value occurs in a sequence, using value equality."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "sequence function"
|
||||
syntax: "index-of(sequence, value, collation?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`index-of()` searches a sequence for all occurrences of a given value and returns a sequence of the 1-based positions where matches are found. If the value does not appear in the sequence, the function returns an empty sequence.
|
||||
|
||||
Value equality follows the same rules as the `=` operator: numeric equality for numbers, Unicode codepoint comparison for strings (unless a collation is specified), and so on. The function compares atomic values; if `sequence` contains nodes, their typed values are compared.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | xs:anyAtomicType* | Yes | The sequence to search. |
|
||||
| `value` | xs:anyAtomicType | Yes | The value to look for. |
|
||||
| `collation` | xs:string | No | A collation URI for string comparison. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer*` — a sequence of 1-based positions where `value` equals the item in `sequence`. Returns an empty sequence if no match is found.
|
||||
|
||||
## Examples
|
||||
|
||||
### Finding where a value appears
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<results>
|
||||
<!-- Positions of 'B' in the sequence -->
|
||||
<xsl:variable name="positions"
|
||||
select="index-of(('A','B','C','B','D','B'), 'B')"/>
|
||||
<positions><xsl:value-of select="$positions" separator=", "/></positions>
|
||||
<!-- First occurrence -->
|
||||
<first><xsl:value-of select="$positions[1]"/></first>
|
||||
<!-- Check if value is present -->
|
||||
<found><xsl:value-of select="exists($positions)"/></found>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<positions>2, 4, 6</positions>
|
||||
<first>2</first>
|
||||
<found>true</found>
|
||||
</results>
|
||||
```
|
||||
|
||||
### Checking attribute value membership
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config>
|
||||
<allowed-formats>pdf xml html txt</allowed-formats>
|
||||
<request format="html"/>
|
||||
<request format="docx"/>
|
||||
</config>
|
||||
```
|
||||
|
||||
**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="/config">
|
||||
<xsl:variable name="formats"
|
||||
select="tokenize(allowed-formats, '\s+')"/>
|
||||
<validation>
|
||||
<xsl:for-each select="request">
|
||||
<xsl:variable name="fmt" select="@format"/>
|
||||
<request format="{$fmt}"
|
||||
allowed="{if (exists(index-of($formats, $fmt))) then 'yes' else 'no'}"/>
|
||||
</xsl:for-each>
|
||||
</validation>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<validation>
|
||||
<request format="html" allowed="yes"/>
|
||||
<request format="docx" allowed="no"/>
|
||||
</validation>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Positions are 1-based, consistent with XPath conventions (as in `position()`, `substring()`, `subsequence()`).
|
||||
- For a simple membership test, the `=` operator with a sequence is often more readable: `$value = $sequence`.
|
||||
- `index-of()` returns all matching positions, not just the first. Use `[1]` to get only the first.
|
||||
- The function operates on atomic values. Nodes in the sequence are atomized before comparison.
|
||||
|
||||
## See also
|
||||
|
||||
- [distinct-values()](../xpath-distinct-values)
|
||||
- [subsequence()](../xpath-subsequence)
|
||||
- [remove()](../xpath-remove)
|
||||
- [insert-before()](../xpath-insert-before)
|
||||
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: "innermost()"
|
||||
description: "Returns the nodes from the input that are not ancestors of any other node in the input sequence."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "node function"
|
||||
syntax: "innermost(nodes)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`innermost()` filters a sequence of nodes to keep only those that are not ancestors of any other node in the same sequence. In other words, it removes from the sequence any node that has a descendant also present in the sequence, retaining only the deepest nodes.
|
||||
|
||||
The result is returned in document order. `innermost()` is the complement of `outermost()`: where `outermost()` keeps the highest ancestors, `innermost()` keeps the lowest descendants. Together they let you work with the boundaries of an overlapping selection.
|
||||
|
||||
This function is especially useful when combining results from multiple XPath expressions that may select nodes at different levels of the same subtree.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `nodes` | node()* | Yes | The sequence of nodes to filter. |
|
||||
|
||||
## Return value
|
||||
|
||||
`node()*` — the subset of input nodes that have no descendants in the input sequence, in document order.
|
||||
|
||||
## Examples
|
||||
|
||||
### Filtering to leaf-level selections
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doc>
|
||||
<section id="s1">
|
||||
<para id="p1">First</para>
|
||||
<para id="p2">Second</para>
|
||||
</section>
|
||||
</doc>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/doc">
|
||||
<!-- Both section and para are in the union -->
|
||||
<xsl:variable name="all" select="section | section/para"/>
|
||||
<innermost-result>
|
||||
<xsl:for-each select="innermost($all)">
|
||||
<node id="{@id}"/>
|
||||
</xsl:for-each>
|
||||
</innermost-result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<innermost-result>
|
||||
<node id="p1"/>
|
||||
<node id="p2"/>
|
||||
</innermost-result>
|
||||
```
|
||||
|
||||
### Comparing innermost and outermost
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/doc">
|
||||
<xsl:variable name="all" select="section | section/para"/>
|
||||
<comparison>
|
||||
<innermost count="{count(innermost($all))}"/>
|
||||
<outermost count="{count(outermost($all))}"/>
|
||||
</comparison>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<comparison>
|
||||
<innermost count="2"/>
|
||||
<outermost count="1"/>
|
||||
</comparison>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- If no node in the sequence is an ancestor of any other, `innermost()` returns the full sequence in document order.
|
||||
- If the sequence contains a single node, `innermost()` returns that same node.
|
||||
- `innermost()` eliminates redundancy when merging selections that may overlap at different levels of nesting.
|
||||
- The result is always in document order regardless of the input order.
|
||||
|
||||
## See also
|
||||
|
||||
- [outermost()](../xpath-outermost)
|
||||
- [has-children()](../xpath-has-children)
|
||||
- [path()](../xpath-path)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "insert-before()"
|
||||
description: "Returns a new sequence with one or more items inserted at a specified 1-based position, without modifying the original sequence."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "sequence function"
|
||||
syntax: "insert-before(sequence, position, insert)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`insert-before()` constructs a new sequence by inserting all items from `insert` immediately before the item at `position` in `sequence`. The original sequence is not modified — XPath sequences are immutable values.
|
||||
|
||||
Position is 1-based. Special cases:
|
||||
|
||||
- If `position` is less than 1, the inserted items are placed at the beginning.
|
||||
- If `position` is greater than the length of `sequence`, the inserted items are placed at the end.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | item()* | Yes | The original sequence. |
|
||||
| `position` | xs:integer | Yes | The 1-based position before which insertion occurs. |
|
||||
| `insert` | item()* | Yes | The items to insert. May be a single item or a sequence. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — a new sequence with the inserted items at the specified position.
|
||||
|
||||
## Examples
|
||||
|
||||
### Inserting a header item into a sequence
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<xsl:variable name="colors" select="('red', 'green', 'blue')"/>
|
||||
<!-- Insert 'yellow' before position 2 -->
|
||||
<xsl:variable name="extended"
|
||||
select="insert-before($colors, 2, 'yellow')"/>
|
||||
<colors>
|
||||
<xsl:for-each select="$extended">
|
||||
<color><xsl:value-of select="."/></color>
|
||||
</xsl:for-each>
|
||||
</colors>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<colors>
|
||||
<color>red</color>
|
||||
<color>yellow</color>
|
||||
<color>green</color>
|
||||
<color>blue</color>
|
||||
</colors>
|
||||
```
|
||||
|
||||
### Building a sequence with a separator between items
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<steps>
|
||||
<step>Init</step>
|
||||
<step>Process</step>
|
||||
<step>Validate</step>
|
||||
<step>Done</step>
|
||||
</steps>
|
||||
```
|
||||
|
||||
**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="/steps">
|
||||
<!-- Insert 'Then:' label before position 2 -->
|
||||
<xsl:variable name="step-labels" select="step/string()"/>
|
||||
<xsl:variable name="with-label"
|
||||
select="insert-before($step-labels, 2, '→')"/>
|
||||
<pipeline>
|
||||
<xsl:value-of select="$with-label" separator=" "/>
|
||||
</pipeline>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<pipeline>Init → Process Validate Done</pipeline>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `insert-before()` is a functional operation — the original sequence is unchanged. Assign the result to a new variable.
|
||||
- `insert-before($seq, 1, $item)` is equivalent to prepending: result is `($item, $seq...)`.
|
||||
- `insert-before($seq, count($seq)+1, $item)` is equivalent to appending: result is `($seq..., $item)`.
|
||||
- The `insert` argument may itself be a sequence, allowing multiple items to be inserted at once.
|
||||
|
||||
## See also
|
||||
|
||||
- [remove()](../xpath-remove)
|
||||
- [subsequence()](../xpath-subsequence)
|
||||
- [reverse()](../xpath-reverse)
|
||||
- [index-of()](../xpath-index-of)
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: "json-doc()"
|
||||
description: "Retrieves a JSON document from a URI and parses it into XDM value using the same rules as parse-json()."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "JSON function"
|
||||
syntax: "json-doc(uri, options?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`json-doc()` loads a JSON document from a URI and returns it as an XDM value using the same mapping rules as `parse-json()`. JSON objects become XDM maps, JSON arrays become XDM arrays, and scalar JSON values become corresponding XDM atomic types. The function is the JSON counterpart to `doc()` for XML documents.
|
||||
|
||||
The `options` map accepts the same keys as `parse-json()`. The URI is resolved against the base URI of the stylesheet. If the URI cannot be dereferenced or the content is not valid JSON, a dynamic error is raised.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `uri` | xs:string? | Yes | The URI of the JSON resource to load. Returns empty sequence if the URI is the empty sequence. |
|
||||
| `options` | map(xs:string, item())? | No | Parsing options, same as for parse-json(). |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()?` — the parsed JSON content as an XDM map, array, or atomic value.
|
||||
|
||||
## Examples
|
||||
|
||||
### Loading a JSON configuration file
|
||||
|
||||
**JSON file (config.json):**
|
||||
```json
|
||||
{
|
||||
"host": "db.example.com",
|
||||
"port": 5432,
|
||||
"database": "production"
|
||||
}
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="cfg" select="json-doc('config.json')"/>
|
||||
<config>
|
||||
<host><xsl:value-of select="map:get($cfg, 'host')"/></host>
|
||||
<port><xsl:value-of select="map:get($cfg, 'port')"/></port>
|
||||
<database><xsl:value-of select="map:get($cfg, 'database')"/></database>
|
||||
</config>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<config>
|
||||
<host>db.example.com</host>
|
||||
<port>5432</port>
|
||||
<database>production</database>
|
||||
</config>
|
||||
```
|
||||
|
||||
### Loading a JSON array from a URL
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="items" select="json-doc('https://api.example.com/items')"/>
|
||||
<items>
|
||||
<xsl:for-each select="1 to array:size($items)">
|
||||
<xsl:variable name="item" select="array:get($items, .)"/>
|
||||
<item name="{map:get($item, 'name')}"/>
|
||||
</xsl:for-each>
|
||||
</items>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<items>
|
||||
<item name="Widget"/>
|
||||
<item name="Gadget"/>
|
||||
</items>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `json-doc()` caches results in the same way as `doc()`; multiple calls with the same URI within a transformation return the same XDM value.
|
||||
- Unlike `doc()`, the result is not a node tree but an XDM atomic or composite value, so you cannot navigate it with XPath axis steps.
|
||||
- The function is not available in XSLT 2.0; use `parse-json(unparsed-text(uri))` as a workaround in 2.0 processors that support `unparsed-text()`.
|
||||
- Relative URIs are resolved against the static base URI of the calling expression.
|
||||
|
||||
## See also
|
||||
|
||||
- [parse-json()](../xpath-parse-json)
|
||||
- [json-to-xml()](../xpath-json-to-xml)
|
||||
- [xml-to-json()](../xpath-xml-to-json)
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
title: "json-to-xml()"
|
||||
description: "Converts a JSON string to its W3C standard XML representation, producing an element tree navigable with XPath."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "JSON function"
|
||||
syntax: "json-to-xml(string, options?)"
|
||||
tags: ["xslt", "reference", "xslt3", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`json-to-xml()` parses a JSON string and converts it into an XML element tree following the W3C XSLT 3.0 specification for the JSON-to-XML mapping. Every JSON construct is represented as an element in the `http://www.w3.org/2005/xpath-functions` namespace: objects become `<map>` elements, arrays become `<array>` elements, strings become `<string>`, numbers become `<number>`, booleans become `<boolean>`, and null becomes `<null>`. Object keys are stored in a `key` attribute.
|
||||
|
||||
The result is a proper XML node tree, so it can be queried with standard XPath axis steps, processed with `xsl:apply-templates`, or further transformed. To go the other way (XML back to JSON text), use `xml-to-json()`. To obtain an XDM map/array instead of an XML tree, use `parse-json()`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | `xs:string?` | Yes | The JSON string to convert. Returns empty sequence if empty. |
|
||||
| `options` | `map(xs:string, item()*)` | No | A map of options; `"liberal"` (boolean) relaxes strict JSON parsing. |
|
||||
|
||||
## Return value
|
||||
|
||||
`document-node()?` — a document node whose root element is a `<map>`, `<array>`, or scalar element in the `http://www.w3.org/2005/xpath-functions` namespace, or empty sequence if the input is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Converting a JSON object to XML and reading properties
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fn="http://www.w3.org/2005/xpath-functions">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="json"
|
||||
select="'{"name":"Alice","age":30,"active":true}'"/>
|
||||
<xsl:variable name="xml" select="json-to-xml($json)"/>
|
||||
<person>
|
||||
<name><xsl:value-of select="$xml//fn:string[@key='name']"/></name>
|
||||
<age><xsl:value-of select="$xml//fn:number[@key='age']"/></age>
|
||||
<active><xsl:value-of select="$xml//fn:boolean[@key='active']"/></active>
|
||||
</person>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<person>
|
||||
<name>Alice</name>
|
||||
<age>30</age>
|
||||
<active>true</active>
|
||||
</person>
|
||||
```
|
||||
|
||||
### Converting a JSON array and applying templates to each member
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<report/>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fn="http://www.w3.org/2005/xpath-functions">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="json" select="unparsed-text('cities.json')"/>
|
||||
<xsl:variable name="xml" select="json-to-xml($json)"/>
|
||||
<cities>
|
||||
<xsl:apply-templates select="$xml/fn:array/fn:map"/>
|
||||
</cities>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="fn:map">
|
||||
<city name="{fn:string[@key='city']}">
|
||||
<population><xsl:value-of select="fn:number[@key='pop']"/></population>
|
||||
</city>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
Assuming `cities.json` contains `[{"city":"Paris","pop":2161000},{"city":"Lyon","pop":516092}]`:
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<cities>
|
||||
<city name="Paris">
|
||||
<population>2161000</population>
|
||||
</city>
|
||||
<city name="Lyon">
|
||||
<population>516092</population>
|
||||
</city>
|
||||
</cities>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The namespace URI for generated elements is `http://www.w3.org/2005/xpath-functions`. Bind it to a prefix (commonly `fn`) in your stylesheet to use axis steps efficiently.
|
||||
- Object keys that are not valid XML `NCName` values are still stored verbatim in the `key` attribute; use `@key = 'the-key'` to match them.
|
||||
- For deeply nested or large JSON structures, `xsl:apply-templates` with mode-based pattern matching is more maintainable than long `//` descendant paths.
|
||||
- If you only need value access by key and not full axis navigation, `parse-json()` returning XDM maps and arrays is simpler.
|
||||
|
||||
## See also
|
||||
|
||||
- [xml-to-json()](../xpath-xml-to-json)
|
||||
- [parse-json()](../xpath-parse-json)
|
||||
- [json-doc()](../xpath-json-doc)
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "lang()"
|
||||
description: "Returns true if the context node's xml:lang attribute matches the given language code, following BCP 47 prefix rules."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "string function"
|
||||
syntax: "lang(string)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`lang()` tests whether the context node is written in the language identified by the argument string. It walks up the ancestor-or-self axis to find the nearest `xml:lang` attribute and then compares its value to the argument using a case-insensitive prefix match.
|
||||
|
||||
The matching rule is: if the `xml:lang` value equals the argument (case-insensitive), or if it equals the argument followed by a hyphen (`-`) and any subtag, then `lang()` returns `true`. For example, `lang('en')` returns `true` for nodes where `xml:lang` is `en`, `en-US`, `en-GB`, or `EN-AU`.
|
||||
|
||||
This makes `lang()` well-suited for filtering multilingual documents by language family without needing to enumerate every regional variant explicitly.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string | Yes | The language code to test against (e.g. `"en"`, `"fr"`, `"zh-Hant"`). |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the context node's effective `xml:lang` matches the argument, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Filter paragraphs by language
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doc>
|
||||
<para xml:lang="en">Hello, world.</para>
|
||||
<para xml:lang="fr">Bonjour le monde.</para>
|
||||
<para xml:lang="en-GB">Cheers, mate.</para>
|
||||
</doc>
|
||||
```
|
||||
|
||||
**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="/doc">
|
||||
<english>
|
||||
<xsl:for-each select="para[lang('en')]">
|
||||
<p><xsl:value-of select="."/></p>
|
||||
</xsl:for-each>
|
||||
</english>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<english>
|
||||
<p>Hello, world.</p>
|
||||
<p>Cheers, mate.</p>
|
||||
</english>
|
||||
```
|
||||
|
||||
### Inherited xml:lang from ancestor
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<book xml:lang="de">
|
||||
<chapter>
|
||||
<title>Einleitung</title>
|
||||
<para>Ein einleitender Absatz.</para>
|
||||
<para xml:lang="en">An English aside.</para>
|
||||
</chapter>
|
||||
</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="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/book">
|
||||
<german-content>
|
||||
<xsl:for-each select="//para[lang('de')]">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</german-content>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<german-content>
|
||||
<item>Ein einleitender Absatz.</item>
|
||||
</german-content>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The comparison is **case-insensitive**: `lang('EN')` and `lang('en')` behave identically.
|
||||
- `lang()` searches the **nearest ancestor-or-self** that carries an `xml:lang` attribute. If no such ancestor exists, the function returns `false`.
|
||||
- The argument is matched as a **prefix**: `lang('zh')` matches `zh-Hant` and `zh-Hans` but not `zho`.
|
||||
- `lang()` only recognises the `xml:lang` attribute in the XML namespace. A plain `lang` attribute without the `xml:` prefix is ignored.
|
||||
- In XSLT 2.0+, `lang()` is still available with the same semantics; additionally, the `xsl:sort` element's `lang` attribute drives language-sensitive collation separately.
|
||||
|
||||
## See also
|
||||
|
||||
- [normalize-space()](../xpath-normalize-space)
|
||||
- [string()](../xpath-string)
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
title: "local-name-from-QName()"
|
||||
description: "Returns the local part of an xs:QName value as an xs:NCName."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "QName function"
|
||||
syntax: "local-name-from-QName(qname)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`local-name-from-QName()` extracts the local part of an `xs:QName` value. The local name is the part after the colon in a prefixed name, or the entire name when no prefix is present. The result is an `xs:NCName` (a non-colonized name), which is a subtype of `xs:string`.
|
||||
|
||||
This function works with `xs:QName` values — typed values produced by `QName()`, `resolve-QName()`, or schema-validated content — not raw string representations of names. If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `qname` | xs:QName? | Yes | The QName from which to extract the local name. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:NCName?` — the local part of the QName, or the empty sequence if the argument is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Extracting local names from constructed QNames
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<names>
|
||||
<local><xsl:value-of select="local-name-from-QName(QName('http://example.com', 'ex:product'))"/></local>
|
||||
<local><xsl:value-of select="local-name-from-QName(QName('', 'simple'))"/></local>
|
||||
</names>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<names>
|
||||
<local>product</local>
|
||||
<local>simple</local>
|
||||
</names>
|
||||
```
|
||||
|
||||
### Using with node-name()
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ns:root xmlns:ns="http://example.com">
|
||||
<ns:child>text</ns:child>
|
||||
</ns:root>
|
||||
```
|
||||
|
||||
**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="/ns:root" xmlns:ns="http://example.com">
|
||||
<result>
|
||||
<xsl:for-each select="*">
|
||||
<element local="{local-name-from-QName(node-name(.))}"/>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<element local="child"/>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `local-name-from-QName()` operates on typed `xs:QName` values, not on string representations. To get the local name of a node, use `local-name()` instead.
|
||||
- The result is identical to `local-name()` on a node whose expanded name matches the QName.
|
||||
- When working with dynamically constructed QNames, this function is the companion to `namespace-uri-from-QName()` and `prefix-from-QName()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [namespace-uri-from-QName()](../xpath-namespace-uri-from-qname)
|
||||
- [prefix-from-QName()](../xpath-prefix-from-qname)
|
||||
- [resolve-QName()](../xpath-resolve-qname)
|
||||
- [QName()](../xpath-qname)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: "local-name()"
|
||||
description: "Returns the local part of the expanded name of a node, stripping any namespace prefix."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "local-name(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`local-name()` returns the local part of a node's name — that is, the part of the qualified name after the colon, or the full name if no prefix is present. For example, a node named `xhtml:div` has a local name of `div`.
|
||||
|
||||
When called without an argument, it returns the local name of the context node. When called with a node-set argument, it returns the local name of the first node in the node-set in document order. For nodes without an expanded name (such as text nodes, comments, and processing instructions with no target), the function returns the empty string `""`.
|
||||
|
||||
`local-name()` is useful when writing stylesheets that must process elements regardless of the namespace prefix used, or when generating output where you want to replicate element names without their prefix.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node-set | No | The node whose local name to return. Defaults to the context node. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the local part of the node's name, or `""` for nodes with no name.
|
||||
|
||||
## Examples
|
||||
|
||||
### Print the local name of each element
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root xmlns:ns="http://example.com/ns">
|
||||
<ns:title>Main Title</ns:title>
|
||||
<ns:body>Body content</ns:body>
|
||||
<plain>Plain element</plain>
|
||||
</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">
|
||||
<names>
|
||||
<xsl:for-each select="*">
|
||||
<item local="{local-name()}" qualified="{name()}"/>
|
||||
</xsl:for-each>
|
||||
</names>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<names>
|
||||
<item local="title" qualified="ns:title"/>
|
||||
<item local="body" qualified="ns:body"/>
|
||||
<item local="plain" qualified="plain"/>
|
||||
</names>
|
||||
```
|
||||
|
||||
### Generic copy stripping namespace prefixes
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data xmlns:d="http://example.com/data">
|
||||
<d:record>
|
||||
<d:field>Value</d:field>
|
||||
</d:record>
|
||||
</data>
|
||||
```
|
||||
|
||||
**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="*">
|
||||
<xsl:element name="{local-name()}">
|
||||
<xsl:apply-templates select="@* | node()"/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="@*">
|
||||
<xsl:attribute name="{local-name()}">
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:attribute>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<data>
|
||||
<record>
|
||||
<field>Value</field>
|
||||
</record>
|
||||
</data>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- For element and attribute nodes, `local-name()` returns the NCName portion after the colon. For unprefixed elements, the local name equals the qualified name.
|
||||
- For text nodes, comment nodes, and document nodes, `local-name()` returns `""`.
|
||||
- Processing instruction nodes return the PI target as their local name.
|
||||
- `local-name()` and `name()` return the same value for nodes with no namespace prefix.
|
||||
- In XSLT 2.0+, `fn:local-name()` is unchanged but also accepts a single node as argument (not a node-set); passing more than one node is an error.
|
||||
|
||||
## See also
|
||||
|
||||
- [name()](../xpath-name)
|
||||
- [namespace-uri()](../xpath-namespace-uri)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: "lower-case()"
|
||||
description: "Converts every character of a string to its Unicode lowercase equivalent using locale-independent Unicode case mapping."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "lower-case(string)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`lower-case()` returns a copy of the input string with every character converted to lowercase according to Unicode default case mappings. The conversion is locale-independent. If the argument is an empty sequence, the function returns the empty string `""`.
|
||||
|
||||
It is the complement of `upper-case()` and is frequently used for normalization before comparison, sorting, or searching — ensuring that strings like `"XML"`, `"xml"`, and `"Xml"` are treated identically.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string? | Yes | The string to convert. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the input string with all characters mapped to lowercase.
|
||||
|
||||
## Examples
|
||||
|
||||
### Normalizing element text for comparison
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tags>
|
||||
<tag>XSLT</tag>
|
||||
<tag>XPath</tag>
|
||||
<tag>xml</tag>
|
||||
<tag>JSON</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="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/tags">
|
||||
<normalized>
|
||||
<xsl:for-each select="tag">
|
||||
<tag><xsl:value-of select="lower-case(.)"/></tag>
|
||||
</xsl:for-each>
|
||||
</normalized>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<normalized>
|
||||
<tag>xslt</tag>
|
||||
<tag>xpath</tag>
|
||||
<tag>xml</tag>
|
||||
<tag>json</tag>
|
||||
</normalized>
|
||||
```
|
||||
|
||||
### Generating lowercase slugs for URLs
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<articles>
|
||||
<article title="Getting Started With XSLT"/>
|
||||
<article title="Advanced XPath Techniques"/>
|
||||
</articles>
|
||||
```
|
||||
|
||||
**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="/articles">
|
||||
<links>
|
||||
<xsl:for-each select="article">
|
||||
<xsl:variable name="slug"
|
||||
select="lower-case(replace(@title, '\s+', '-'))"/>
|
||||
<a href="/articles/{$slug}"><xsl:value-of select="@title"/></a>
|
||||
</xsl:for-each>
|
||||
</links>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<links>
|
||||
<a href="/articles/getting-started-with-xslt">Getting Started With XSLT</a>
|
||||
<a href="/articles/advanced-xpath-techniques">Advanced XPath Techniques</a>
|
||||
</links>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Like `upper-case()`, this function uses Unicode default case mappings and is not locale-aware.
|
||||
- It does not modify digits, punctuation, or whitespace.
|
||||
- Combining `lower-case()` with `normalize-unicode()` is good practice when normalizing data from multiple sources before comparison.
|
||||
- In XSLT 1.0, the nearest equivalent is `translate()` with explicit letter-by-letter mapping, which is cumbersome for full Unicode support.
|
||||
|
||||
## See also
|
||||
|
||||
- [upper-case()](../xpath-upper-case)
|
||||
- [normalize-unicode()](../xpath-normalize-unicode)
|
||||
- [normalize-space()](../xpath-normalize-space)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "map:contains()"
|
||||
description: "Returns true if a map contains an entry with the specified key, false otherwise."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:contains(map, key)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:contains()` tests whether a map has an entry for a given key. The key comparison uses the same rules as map lookup (XDM equality for atomic values). This is preferable to checking `map:get()` for the empty sequence, because a key may legitimately map to the empty sequence.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `map` | map(*) | Yes | The map to test. |
|
||||
| `key` | xs:anyAtomicType | Yes | The key to look for. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the map contains the key, `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
### Safe conditional lookup
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="settings" select="map{
|
||||
'debug': true(),
|
||||
'timeout': 30
|
||||
}"/>
|
||||
<config>
|
||||
<has-debug><xsl:value-of select="map:contains($settings, 'debug')"/></has-debug>
|
||||
<has-verbose><xsl:value-of select="map:contains($settings, 'verbose')"/></has-verbose>
|
||||
<debug-value>
|
||||
<xsl:if test="map:contains($settings, 'debug')">
|
||||
<xsl:value-of select="map:get($settings, 'debug')"/>
|
||||
</xsl:if>
|
||||
</debug-value>
|
||||
</config>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<config>
|
||||
<has-debug>true</has-debug>
|
||||
<has-verbose>false</has-verbose>
|
||||
<debug-value>true</debug-value>
|
||||
</config>
|
||||
```
|
||||
|
||||
### Filtering a map by known keys
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="data" select="map{
|
||||
'name':'Alice', 'age':30, 'ssn':'123-45-6789', 'city':'Paris'
|
||||
}"/>
|
||||
<xsl:variable name="allowed" select="('name', 'age', 'city')"/>
|
||||
<safe-output>
|
||||
<xsl:for-each select="$allowed[map:contains($data, .)]">
|
||||
<xsl:element name="{.}">
|
||||
<xsl:value-of select="map:get($data, .)"/>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
</safe-output>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<safe-output>
|
||||
<name>Alice</name>
|
||||
<age>30</age>
|
||||
<city>Paris</city>
|
||||
</safe-output>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Use `map:contains()` instead of `exists(map:get(...))` when a key may map to the empty sequence `()`.
|
||||
- Key comparison is type-aware: `map:contains($m, 1)` and `map:contains($m, '1')` are different lookups.
|
||||
- For checking multiple keys, combine with `every ... satisfies` or `some ... satisfies`.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:get()](../xpath-map-get)
|
||||
- [map:keys()](../xpath-map-keys)
|
||||
- [map:size()](../xpath-map-size)
|
||||
- [map:put()](../xpath-map-put)
|
||||
- [xsl:map](../xsl-map)
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: "map:entry()"
|
||||
description: "Creates a singleton map containing exactly one key-value pair."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:entry(key, value)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:entry()` constructs a map with a single key-value entry. It is primarily useful when building maps programmatically — for example, inside `for` expressions or `fold-left()` accumulations — and then combining the singleton maps with `map:merge()`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `key` | xs:anyAtomicType | Yes | The key of the entry. |
|
||||
| `value` | item()* | Yes | The value to associate with the key. |
|
||||
|
||||
## Return value
|
||||
|
||||
`map(xs:anyAtomicType, item()*)` — a singleton map with one entry.
|
||||
|
||||
## Examples
|
||||
|
||||
### Building a map from XML nodes
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config>
|
||||
<entry key="host">example.com</entry>
|
||||
<entry key="port">443</entry>
|
||||
<entry key="tls">true</entry>
|
||||
</config>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/config">
|
||||
<xsl:variable name="cfg" select="map:merge(
|
||||
for $e in entry return map:entry(string($e/@key), string($e))
|
||||
)"/>
|
||||
<result>
|
||||
<host><xsl:value-of select="map:get($cfg, 'host')"/></host>
|
||||
<port><xsl:value-of select="map:get($cfg, 'port')"/></port>
|
||||
<tls><xsl:value-of select="map:get($cfg, 'tls')"/></tls>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<host>example.com</host>
|
||||
<port>443</port>
|
||||
<tls>true</tls>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Accumulating a frequency map
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="words" select="('cat', 'dog', 'cat', 'bird', 'dog', 'cat')"/>
|
||||
<xsl:variable name="freq" select="fold-left($words, map{},
|
||||
function($acc, $w) {
|
||||
map:put($acc, $w, (map:get($acc, $w), 0)[1] + 1)
|
||||
}
|
||||
)"/>
|
||||
<frequencies>
|
||||
<xsl:for-each select="sort(map:keys($freq))">
|
||||
<word count="{map:get($freq, .)}"><xsl:value-of select="."/></word>
|
||||
</xsl:for-each>
|
||||
</frequencies>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<frequencies>
|
||||
<word count="1">bird</word>
|
||||
<word count="2">dog</word>
|
||||
<word count="3">cat</word>
|
||||
</frequencies>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `map:entry($k, $v)` is equivalent to the map constructor `map{$k: $v}`.
|
||||
- Particularly useful inside `for` expressions where the map constructor syntax is awkward.
|
||||
- Combine multiple `map:entry()` results with `map:merge()` to build larger maps.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:get()](../xpath-map-get)
|
||||
- [map:put()](../xpath-map-put)
|
||||
- [map:merge()](../xpath-map-merge)
|
||||
- [xsl:map](../xsl-map)
|
||||
- [xsl:map-entry](../xsl-map-entry)
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
title: "map:get()"
|
||||
description: "Returns the value associated with a key in a map, or the empty sequence if the key is not present."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:get(map, key)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:get()` retrieves the value associated with a given key in a map. If the key does not exist, the empty sequence is returned — not an error. Because the empty sequence can also be a legitimate value, use `map:contains()` to distinguish "key absent" from "key maps to empty sequence".
|
||||
|
||||
An alternative shorthand is `$map($key)` using function-call syntax on a map.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `map` | map(*) | Yes | The map to look up. |
|
||||
| `key` | xs:anyAtomicType | Yes | The key whose value is to be retrieved. |
|
||||
|
||||
## Return value
|
||||
|
||||
`item()*` — the value associated with the key, or the empty sequence if absent.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic map lookup
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="capitals" select="map{
|
||||
'France': 'Paris',
|
||||
'Germany': 'Berlin',
|
||||
'Japan': 'Tokyo'
|
||||
}"/>
|
||||
<capitals>
|
||||
<xsl:for-each select="('France', 'Japan', 'Italy')">
|
||||
<country name="{.}">
|
||||
<xsl:value-of select="(map:get($capitals, .), 'Unknown')[1]"/>
|
||||
</country>
|
||||
</xsl:for-each>
|
||||
</capitals>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<capitals>
|
||||
<country name="France">Paris</country>
|
||||
<country name="Japan">Tokyo</country>
|
||||
<country name="Italy">Unknown</country>
|
||||
</capitals>
|
||||
```
|
||||
|
||||
### Using function-call shorthand $map($key)
|
||||
|
||||
**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="/">
|
||||
<xsl:variable name="prices" select="map{
|
||||
'apple': 0.99,
|
||||
'banana': 0.59,
|
||||
'cherry': 2.49
|
||||
}"/>
|
||||
<!-- Both syntaxes are equivalent -->
|
||||
<prices>
|
||||
<item>apple: <xsl:value-of select="$prices('apple')"/></item>
|
||||
<item>banana: <xsl:value-of select="map:get($prices, 'banana')"/></item>
|
||||
</prices>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<prices>
|
||||
<item>apple: 0.99</item>
|
||||
<item>banana: 0.59</item>
|
||||
</prices>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `map:get()` and `$map($key)` are equivalent; the shorthand is more concise for inline expressions.
|
||||
- Returns the empty sequence (not an error) for missing keys; use `map:contains()` when you need to distinguish absence from an empty-sequence value.
|
||||
- Key comparison is type-aware: `xs:integer(1)` and `xs:string('1')` are different keys.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:contains()](../xpath-map-contains)
|
||||
- [map:put()](../xpath-map-put)
|
||||
- [map:keys()](../xpath-map-keys)
|
||||
- [map:entry()](../xpath-map-entry)
|
||||
- [xsl:map](../xsl-map)
|
||||
- [xsl:map-entry](../xsl-map-entry)
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: "map:keys()"
|
||||
description: "Returns all keys of a map as a sequence of atomic values in implementation-defined order."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:keys(map)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:keys()` returns a sequence containing all the keys present in a map. The order of keys in the result is implementation-defined and should not be relied upon. Keys are always atomic values (`xs:anyAtomicType`). For an empty map, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `map` | map(*) | Yes | The map whose keys are to be returned. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyAtomicType*` — a sequence of all keys in the map; empty sequence for an empty map.
|
||||
|
||||
## Examples
|
||||
|
||||
### Iterating over all map keys
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="scores" select="map{
|
||||
'Alice': 95,
|
||||
'Bob': 82,
|
||||
'Carol': 91
|
||||
}"/>
|
||||
<report>
|
||||
<xsl:for-each select="sort(map:keys($scores))">
|
||||
<student name="{.}" score="{map:get($scores, .)}"/>
|
||||
</xsl:for-each>
|
||||
</report>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<report>
|
||||
<student name="Alice" score="95"/>
|
||||
<student name="Bob" score="82"/>
|
||||
<student name="Carol" score="91"/>
|
||||
</report>
|
||||
```
|
||||
|
||||
### Converting a map to XML elements
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="config" select="map{
|
||||
'theme': 'dark',
|
||||
'lang': 'en',
|
||||
'version': '3.0'
|
||||
}"/>
|
||||
<config>
|
||||
<xsl:for-each select="sort(map:keys($config))">
|
||||
<xsl:element name="{.}">
|
||||
<xsl:value-of select="map:get($config, .)"/>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
</config>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<config>
|
||||
<lang>en</lang>
|
||||
<theme>dark</theme>
|
||||
<version>3.0</version>
|
||||
</config>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The order of keys is not guaranteed; wrap with `sort()` for deterministic output.
|
||||
- Keys can be any atomic type: `xs:string`, `xs:integer`, `xs:date`, etc.
|
||||
- Duplicate keys cannot exist in a map, so `count(map:keys($m))` always equals `map:size($m)`.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:get()](../xpath-map-get)
|
||||
- [map:contains()](../xpath-map-contains)
|
||||
- [map:size()](../xpath-map-size)
|
||||
- [map:merge()](../xpath-map-merge)
|
||||
- [xsl:map](../xsl-map)
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: "map:merge()"
|
||||
description: "Merges multiple maps into one, with duplicate key handling controlled by an options map."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:merge(maps, options?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:merge()` combines a sequence of maps into a single map. When two or more maps share the same key, the behavior is controlled by the `duplicates` option. The function is immutable — the input maps are not modified; a new map is returned.
|
||||
|
||||
The `duplicates` option accepts: `"reject"` (error), `"use-first"`, `"use-last"` (default), `"combine"` (values become a sequence), or `"unspecified"`.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `maps` | map(*)* | Yes | A sequence of maps to merge. |
|
||||
| `options` | map(xs:string, item())? | No | Options map; key `"duplicates"` controls duplicate handling. |
|
||||
|
||||
## Return value
|
||||
|
||||
`map(*)` — a new map containing all entries from the input maps.
|
||||
|
||||
## Examples
|
||||
|
||||
### Merging two maps with use-last (default)
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="defaults" select="map{'color':'blue', 'size':'medium', 'weight':1}"/>
|
||||
<xsl:variable name="overrides" select="map{'color':'red', 'weight':5}"/>
|
||||
<xsl:variable name="merged" select="map:merge(($defaults, $overrides))"/>
|
||||
<config>
|
||||
<color><xsl:value-of select="map:get($merged, 'color')"/></color>
|
||||
<size><xsl:value-of select="map:get($merged, 'size')"/></size>
|
||||
<weight><xsl:value-of select="map:get($merged, 'weight')"/></weight>
|
||||
</config>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<config>
|
||||
<color>red</color>
|
||||
<size>medium</size>
|
||||
<weight>5</weight>
|
||||
</config>
|
||||
```
|
||||
|
||||
### Merging with combine to accumulate duplicate values
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="m1" select="map{'tag':'xslt', 'tag2':'xml'}"/>
|
||||
<xsl:variable name="m2" select="map{'tag':'xpath'}"/>
|
||||
<xsl:variable name="merged" select="map:merge(($m1, $m2),
|
||||
map{'duplicates':'combine'})"/>
|
||||
<tags>
|
||||
<xsl:for-each select="map:get($merged, 'tag')">
|
||||
<tag><xsl:value-of select="."/></tag>
|
||||
</xsl:for-each>
|
||||
</tags>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<tags>
|
||||
<tag>xslt</tag>
|
||||
<tag>xpath</tag>
|
||||
</tags>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The default duplicate behavior (`use-last`) means later maps in the input sequence win.
|
||||
- `"reject"` causes `err:FOJS0003` when a duplicate key is encountered.
|
||||
- `map:merge()` also accepts an empty sequence, returning an empty map.
|
||||
- Maps are immutable in XDM; merge always produces a new map.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:put()](../xpath-map-put)
|
||||
- [map:remove()](../xpath-map-remove)
|
||||
- [map:get()](../xpath-map-get)
|
||||
- [map:keys()](../xpath-map-keys)
|
||||
- [map:size()](../xpath-map-size)
|
||||
- [xsl:map](../xsl-map)
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "map:put()"
|
||||
description: "Returns a new map with a key-value entry added or updated, leaving the original map unchanged."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:put(map, key, value)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:put()` produces a new map that is identical to the input map except that the given key is associated with the given value. If the key already exists, its value is replaced. If the key is new, the entry is added. Maps are immutable in XDM; the original map is never modified.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `map` | map(*) | Yes | The source map. |
|
||||
| `key` | xs:anyAtomicType | Yes | The key to add or update. |
|
||||
| `value` | item()* | Yes | The value to associate with the key. |
|
||||
|
||||
## Return value
|
||||
|
||||
`map(*)` — a new map with the specified key-value pair added or updated.
|
||||
|
||||
## Examples
|
||||
|
||||
### Adding and updating map entries
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="m0" select="map{'a':1, 'b':2}"/>
|
||||
<xsl:variable name="m1" select="map:put($m0, 'c', 3)"/> <!-- add new key -->
|
||||
<xsl:variable name="m2" select="map:put($m1, 'a', 99)"/> <!-- update existing -->
|
||||
<result>
|
||||
<size><xsl:value-of select="map:size($m2)"/></size>
|
||||
<a><xsl:value-of select="map:get($m2, 'a')"/></a>
|
||||
<b><xsl:value-of select="map:get($m2, 'b')"/></b>
|
||||
<c><xsl:value-of select="map:get($m2, 'c')"/></c>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<size>3</size>
|
||||
<a>99</a>
|
||||
<b>2</b>
|
||||
<c>3</c>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Building a map incrementally from XML
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings>
|
||||
<item key="host">localhost</item>
|
||||
<item key="port">8080</item>
|
||||
<item key="debug">true</item>
|
||||
</settings>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/settings">
|
||||
<xsl:variable name="config" select="fold-left(item, map{},
|
||||
function($acc, $item) { map:put($acc, string($item/@key), string($item)) }
|
||||
)"/>
|
||||
<config>
|
||||
<host><xsl:value-of select="map:get($config, 'host')"/></host>
|
||||
<port><xsl:value-of select="map:get($config, 'port')"/></port>
|
||||
</config>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<config>
|
||||
<host>localhost</host>
|
||||
<port>8080</port>
|
||||
</config>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Maps are immutable; `map:put()` never modifies the original map.
|
||||
- Equivalent to `map:merge(($map, map:entry($key, $value)))` with `duplicates: use-last`.
|
||||
- Chain multiple `map:put()` calls to build up a map from individual entries.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:get()](../xpath-map-get)
|
||||
- [map:remove()](../xpath-map-remove)
|
||||
- [map:entry()](../xpath-map-entry)
|
||||
- [map:merge()](../xpath-map-merge)
|
||||
- [xsl:map](../xsl-map)
|
||||
- [xsl:map-entry](../xsl-map-entry)
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: "map:remove()"
|
||||
description: "Returns a new map with one or more specified keys removed, leaving the original map unchanged."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:remove(map, keys)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:remove()` produces a new map that contains all entries from the input map except those whose keys appear in the `keys` sequence. If a key in `keys` is not present in the map, it is silently ignored. Maps are immutable; the original is not modified.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `map` | map(*) | Yes | The source map. |
|
||||
| `keys` | xs:anyAtomicType* | Yes | A sequence of keys to remove. |
|
||||
|
||||
## Return value
|
||||
|
||||
`map(*)` — a new map with the specified keys removed.
|
||||
|
||||
## Examples
|
||||
|
||||
### Removing a single key
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="user" select="map{
|
||||
'name': 'Alice',
|
||||
'email': 'alice@example.com',
|
||||
'password': 'secret123'
|
||||
}"/>
|
||||
<!-- Remove sensitive field before output -->
|
||||
<xsl:variable name="safe" select="map:remove($user, 'password')"/>
|
||||
<user>
|
||||
<xsl:for-each select="sort(map:keys($safe))">
|
||||
<xsl:element name="{.}"><xsl:value-of select="map:get($safe, .)"/></xsl:element>
|
||||
</xsl:for-each>
|
||||
</user>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<user>
|
||||
<email>alice@example.com</email>
|
||||
<name>Alice</name>
|
||||
</user>
|
||||
```
|
||||
|
||||
### Removing multiple keys at once
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="record" select="map{
|
||||
'id':1, 'name':'Bob', 'ssn':'999-99-9999',
|
||||
'dob':'1990-01-01', 'city':'London'
|
||||
}"/>
|
||||
<xsl:variable name="private-keys" select="('ssn', 'dob')"/>
|
||||
<xsl:variable name="public" select="map:remove($record, $private-keys)"/>
|
||||
<public-record size="{map:size($public)}">
|
||||
<xsl:for-each select="sort(map:keys($public))">
|
||||
<field name="{.}"><xsl:value-of select="map:get($public, .)"/></field>
|
||||
</xsl:for-each>
|
||||
</public-record>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<public-record size="3">
|
||||
<field name="city">London</field>
|
||||
<field name="id">1</field>
|
||||
<field name="name">Bob</field>
|
||||
</public-record>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Removing a non-existent key is not an error; it is silently ignored.
|
||||
- Maps are immutable; `map:remove()` always returns a new map.
|
||||
- To remove all keys, use `map:remove($m, map:keys($m))`, which returns an empty map.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:put()](../xpath-map-put)
|
||||
- [map:get()](../xpath-map-get)
|
||||
- [map:contains()](../xpath-map-contains)
|
||||
- [map:keys()](../xpath-map-keys)
|
||||
- [map:merge()](../xpath-map-merge)
|
||||
- [xsl:map](../xsl-map)
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: "map:size()"
|
||||
description: "Returns the number of key-value entries in a map."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "3.0"
|
||||
versionLabel: "XSLT 3.0"
|
||||
category: "map function"
|
||||
syntax: "map:size(map)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt3"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`map:size()` returns the count of entries (key-value pairs) in a map as an `xs:integer`. An empty map returns `0`. This is the map equivalent of `count()` for sequences.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `map` | map(*) | Yes | The map whose entry count is to be returned. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer` — the number of entries in the map; `0` for an empty map.
|
||||
|
||||
## Examples
|
||||
|
||||
### Counting entries in a map
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:variable name="config" select="map{
|
||||
'host': 'localhost',
|
||||
'port': 8080,
|
||||
'debug': true()
|
||||
}"/>
|
||||
<result>
|
||||
<size><xsl:value-of select="map:size($config)"/></size>
|
||||
<empty><xsl:value-of select="map:size(map{})"/></empty>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<size>3</size>
|
||||
<empty>0</empty>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Using size to validate a map before processing
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<request>
|
||||
<param name="host">example.com</param>
|
||||
<param name="port">443</param>
|
||||
</request>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:map="http://www.w3.org/2005/xpath-functions/map">
|
||||
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/request">
|
||||
<xsl:variable name="params" select="map:merge(
|
||||
for $p in param return map:entry($p/@name, $p/text())
|
||||
)"/>
|
||||
<status>
|
||||
<param-count><xsl:value-of select="map:size($params)"/></param-count>
|
||||
<valid><xsl:value-of select="map:size($params) ge 2"/></valid>
|
||||
</status>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<status>
|
||||
<param-count>2</param-count>
|
||||
<valid>true</valid>
|
||||
</status>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `map:size()` is O(1) in most implementations.
|
||||
- Use `map:size($m) = 0` to check for an empty map (or compare with `map{}`).
|
||||
- The function counts top-level keys only; nested maps inside values count as one entry each.
|
||||
|
||||
## See also
|
||||
|
||||
- [map:keys()](../xpath-map-keys)
|
||||
- [map:get()](../xpath-map-get)
|
||||
- [map:contains()](../xpath-map-contains)
|
||||
- [map:merge()](../xpath-map-merge)
|
||||
- [xsl:map](../xsl-map)
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: "max()"
|
||||
description: "Returns the largest value in a sequence of comparable items, optionally using a named collation for string comparison."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "numeric function"
|
||||
syntax: "max(sequence, collation?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`max()` returns the maximum value from a sequence. It works with any orderable atomic type: numeric types, strings, dates, times, and durations. All items in the sequence must be mutually comparable; mixing incompatible types raises a type error.
|
||||
|
||||
When comparing strings, an optional collation URI controls ordering rules.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | xs:anyAtomicType* | Yes | Sequence of comparable values. |
|
||||
| `collation` | xs:string | No | Collation URI used for string comparison. Defaults to the default collation. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyAtomicType?` — the largest item in the sequence according to the `gt` operator, or the empty sequence if the input is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Maximum numeric value
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<prices>
|
||||
<price>29.99</price>
|
||||
<price>149.00</price>
|
||||
<price>9.50</price>
|
||||
<price>74.95</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"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/prices">
|
||||
<result>
|
||||
<max-price><xsl:value-of select="max(price/xs:decimal(.))"/></max-price>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<max-price>149.00</max-price>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Latest date in a list
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<deadlines>
|
||||
<deadline>2026-05-01</deadline>
|
||||
<deadline>2026-04-15</deadline>
|
||||
<deadline>2026-06-30</deadline>
|
||||
</deadlines>
|
||||
```
|
||||
|
||||
**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="/deadlines">
|
||||
<final-deadline>
|
||||
<xsl:value-of select="max(deadline/xs:date(.))"/>
|
||||
</final-deadline>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<final-deadline>2026-06-30</final-deadline>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Returns the empty sequence (not an error) when the input sequence is empty.
|
||||
- `NaN` propagates: if any item is `xs:double('NaN')`, the result is `NaN`.
|
||||
- The collation parameter is only meaningful for string sequences.
|
||||
- Equivalent to sorting descending and taking the first item, but more concise and efficient.
|
||||
|
||||
## See also
|
||||
|
||||
- [min()](../xpath-min)
|
||||
- [avg()](../xpath-avg)
|
||||
- [abs()](../xpath-abs)
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: "min()"
|
||||
description: "Returns the smallest value in a sequence of comparable items, optionally using a named collation for string comparison."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "numeric function"
|
||||
syntax: "min(sequence, collation?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`min()` returns the minimum value from a sequence. It works with any orderable atomic type: numeric types, strings, dates, times, and durations. All items in the sequence must be mutually comparable; mixing incompatible types raises an error.
|
||||
|
||||
When comparing strings, an optional collation URI controls ordering rules.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `sequence` | xs:anyAtomicType* | Yes | Sequence of comparable values. |
|
||||
| `collation` | xs:string | No | Collation URI used for string comparison. Defaults to the default collation. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyAtomicType?` — the smallest item in the sequence according to the `lt` operator, or the empty sequence if the input is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Minimum numeric value
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<temperatures>
|
||||
<temp>23.5</temp>
|
||||
<temp>18.0</temp>
|
||||
<temp>31.2</temp>
|
||||
<temp>15.7</temp>
|
||||
</temperatures>
|
||||
```
|
||||
|
||||
**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="/temperatures">
|
||||
<result>
|
||||
<min-temp><xsl:value-of select="min(temp/xs:decimal(.))"/></min-temp>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<min-temp>15.7</min-temp>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Earliest date in a sequence
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<events>
|
||||
<event date="2026-06-15">Summer conference</event>
|
||||
<event date="2026-03-01">Spring kickoff</event>
|
||||
<event date="2026-11-20">Year-end review</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">
|
||||
<earliest>
|
||||
<xsl:value-of select="min(event/xs:date(@date))"/>
|
||||
</earliest>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<earliest>2026-03-01</earliest>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Returns the empty sequence (not an error) when the input sequence is empty.
|
||||
- `NaN` propagates: if any item is `xs:double('NaN')`, the result is `NaN`.
|
||||
- Unlike XSLT 1.0 workarounds (`<xsl:sort>` then `[1]`), `min()` is a single expression and works with typed values.
|
||||
- The collation parameter is meaningful only for string sequences.
|
||||
|
||||
## See also
|
||||
|
||||
- [max()](../xpath-max)
|
||||
- [avg()](../xpath-avg)
|
||||
- [abs()](../xpath-abs)
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: "minutes-from-time()"
|
||||
description: "Extracts the minutes component from an xs:time value as an xs:integer in the range 0–59."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "minutes-from-time(time)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`minutes-from-time()` returns the minutes component of an `xs:time` value as an `xs:integer` between 0 and 59. If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `time` | xs:time? | Yes | The time value from which to extract the minutes. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer?` — integer from 0 to 59, or the empty sequence if the argument is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Format a time with zero-padded minutes
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<log>
|
||||
<entry time="08:05:00">System started</entry>
|
||||
<entry time="12:30:00">Lunch break</entry>
|
||||
<entry time="17:45:00">Shutdown</entry>
|
||||
</log>
|
||||
```
|
||||
|
||||
**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="/log">
|
||||
<log>
|
||||
<xsl:for-each select="entry">
|
||||
<xsl:variable name="t" select="xs:time(@time)"/>
|
||||
<entry formatted="{hours-from-time($t)}h{format-number(minutes-from-time($t), '00')}">
|
||||
<xsl:value-of select="."/>
|
||||
</entry>
|
||||
</xsl:for-each>
|
||||
</log>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<log>
|
||||
<entry formatted="8h05">System started</entry>
|
||||
<entry formatted="12h30">Lunch break</entry>
|
||||
<entry formatted="17h45">Shutdown</entry>
|
||||
</log>
|
||||
```
|
||||
|
||||
### Check if an appointment is on the hour
|
||||
|
||||
**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="/schedule">
|
||||
<on-the-hour>
|
||||
<xsl:copy-of select="appointment[minutes-from-time(xs:time(@time)) = 0]"/>
|
||||
</on-the-hour>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The argument must be typed as `xs:time`. Cast string values with `xs:time(@attr)`.
|
||||
- Returns 0–59; does not include fractional minutes (those appear in the seconds component).
|
||||
- For `xs:dateTime` values, use `minutes-from-dateTime()`.
|
||||
|
||||
## See also
|
||||
|
||||
- [hours-from-time()](../xpath-hours-from-time)
|
||||
- [seconds-from-time()](../xpath-seconds-from-time)
|
||||
- [current-time()](../xpath-current-time)
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: "month-from-date()"
|
||||
description: "Extracts the month component from an xs:date value as an xs:integer in the range 1–12."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "date function"
|
||||
syntax: "month-from-date(date)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`month-from-date()` returns the month component of an `xs:date` value as an `xs:integer` between 1 (January) and 12 (December). If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `date` | xs:date? | Yes | The date value from which to extract the month. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:integer?` — integer from 1 to 12 representing the month, or the empty sequence if the argument is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Group events by month
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<events>
|
||||
<event date="2026-04-05">Easter workshop</event>
|
||||
<event date="2026-04-18">Spring conference</event>
|
||||
<event date="2026-06-01">Summer launch</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">
|
||||
<by-month>
|
||||
<xsl:for-each-group select="event" group-by="month-from-date(xs:date(@date))">
|
||||
<month number="{current-grouping-key()}">
|
||||
<xsl:copy-of select="current-group()"/>
|
||||
</month>
|
||||
</xsl:for-each-group>
|
||||
</by-month>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<by-month>
|
||||
<month number="4">
|
||||
<event date="2026-04-05">Easter workshop</event>
|
||||
<event date="2026-04-18">Spring conference</event>
|
||||
</month>
|
||||
<month number="6">
|
||||
<event date="2026-06-01">Summer launch</event>
|
||||
</month>
|
||||
</by-month>
|
||||
```
|
||||
|
||||
### Check if a date falls in the current month
|
||||
|
||||
**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">
|
||||
<this-month>
|
||||
<xsl:copy-of select="event[
|
||||
month-from-date(xs:date(@date)) = month-from-date(current-date()) and
|
||||
year-from-date(xs:date(@date)) = year-from-date(current-date())]"/>
|
||||
</this-month>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The argument must be typed as `xs:date`. Cast string attributes with `xs:date(@attr)`.
|
||||
- Month numbers are 1-based (January = 1, December = 12).
|
||||
- Use alongside `year-from-date()` when filtering by month to avoid false matches across years.
|
||||
|
||||
## See also
|
||||
|
||||
- [year-from-date()](../xpath-year-from-date)
|
||||
- [day-from-date()](../xpath-day-from-date)
|
||||
- [current-date()](../xpath-current-date)
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: "name()"
|
||||
description: "Returns the qualified name (including namespace prefix, if any) of a node as it appears in the source document."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "name(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`name()` returns the qualified name of a node — the same string that appears in the source document, including the namespace prefix if one was used. For an element declared as `<xhtml:div>`, `name()` returns `"xhtml:div"`.
|
||||
|
||||
When called without an argument, it returns the qualified name of the context node. When called with a node-set, it returns the qualified name of the first node in document order.
|
||||
|
||||
For nodes that have no name (text nodes, comment nodes, document nodes), `name()` returns the empty string `""`. Processing instruction nodes return the PI target.
|
||||
|
||||
Note that the prefix returned by `name()` is the prefix used in the **source document**, which may differ from the prefix declared in the stylesheet. If you need a namespace-safe comparison, use `namespace-uri()` and `local-name()` separately rather than relying on prefix equality.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node-set | No | The node whose qualified name to return. Defaults to the context node. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the qualified name of the node as used in the source document, or `""` for unnamed nodes.
|
||||
|
||||
## Examples
|
||||
|
||||
### Report element and attribute names
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<catalog xmlns:ns="http://example.com/ns">
|
||||
<ns:item id="1" ns:category="book">
|
||||
<ns:title>XML in Practice</ns:title>
|
||||
</ns: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">
|
||||
<names>
|
||||
<xsl:for-each select="//ns:item" xmlns:ns="http://example.com/ns">
|
||||
<element name="{name()}"/>
|
||||
<xsl:for-each select="@*">
|
||||
<attribute name="{name()}"/>
|
||||
</xsl:for-each>
|
||||
</xsl:for-each>
|
||||
</names>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<names>
|
||||
<element name="ns:item"/>
|
||||
<attribute name="id"/>
|
||||
<attribute name="ns:category"/>
|
||||
</names>
|
||||
```
|
||||
|
||||
### Dynamic dispatch based on element name
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form>
|
||||
<text-field>username</text-field>
|
||||
<password-field>secret</password-field>
|
||||
<text-field>email</text-field>
|
||||
</form>
|
||||
```
|
||||
|
||||
**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="/form">
|
||||
<fields>
|
||||
<xsl:for-each select="*">
|
||||
<field type="{name()}">
|
||||
<xsl:value-of select="."/>
|
||||
</field>
|
||||
</xsl:for-each>
|
||||
</fields>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<fields>
|
||||
<field type="text-field">username</field>
|
||||
<field type="password-field">secret</field>
|
||||
<field type="text-field">email</field>
|
||||
</fields>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `name()` returns the prefix-qualified name as written in the source document. Two documents can use different prefixes for the same namespace URI; therefore, do not compare `name()` values across documents when namespaces are involved.
|
||||
- For namespace-safe identity comparisons, use `namespace-uri() = 'http://...' and local-name() = 'foo'`.
|
||||
- `name()` and `local-name()` return the same value for unprefixed nodes.
|
||||
- In XSLT 2.0+, `fn:name()` is unchanged but the argument must be zero or one node; node-sets with multiple items raise a type error.
|
||||
|
||||
## See also
|
||||
|
||||
- [local-name()](../xpath-local-name)
|
||||
- [namespace-uri()](../xpath-namespace-uri)
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
title: "namespace-uri-from-QName()"
|
||||
description: "Returns the namespace URI part of an xs:QName value."
|
||||
date: 2026-04-19T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "QName function"
|
||||
syntax: "namespace-uri-from-QName(qname)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`namespace-uri-from-QName()` extracts the namespace URI from an `xs:QName` value. The URI is the string that uniquely identifies the namespace, not the prefix. If the QName has no namespace, the function returns a zero-length string. If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
This function is part of the family of QName accessor functions that decompose an `xs:QName` into its three components: local name, namespace URI, and prefix. The namespace URI is the most stable component because prefixes can be remapped, whereas namespace URIs are authoritative identifiers.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `qname` | xs:QName? | Yes | The QName from which to extract the namespace URI. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:anyURI?` — the namespace URI of the QName, or the empty string if the QName has no namespace, or the empty sequence if the argument is empty.
|
||||
|
||||
## Examples
|
||||
|
||||
### Decomposing a QName
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/">
|
||||
<xsl:variable name="q" select="QName('http://example.com/ns', 'ex:widget')"/>
|
||||
<qname-info>
|
||||
<uri><xsl:value-of select="namespace-uri-from-QName($q)"/></uri>
|
||||
<local><xsl:value-of select="local-name-from-QName($q)"/></local>
|
||||
<prefix><xsl:value-of select="prefix-from-QName($q)"/></prefix>
|
||||
</qname-info>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<qname-info>
|
||||
<uri>http://example.com/ns</uri>
|
||||
<local>widget</local>
|
||||
<prefix>ex</prefix>
|
||||
</qname-info>
|
||||
```
|
||||
|
||||
### Checking the namespace of a node
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root xmlns:app="http://myapp.example.com">
|
||||
<app:item>content</app:item>
|
||||
</root>
|
||||
```
|
||||
|
||||
**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="/root">
|
||||
<xsl:for-each select="*">
|
||||
Namespace URI: <xsl:value-of select="namespace-uri-from-QName(node-name(.))"/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
Namespace URI: http://myapp.example.com
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- For a QName with no namespace (created with `QName('', 'localname')`), the function returns a zero-length `xs:anyURI`, not the empty sequence.
|
||||
- This function is the typed-value equivalent of calling `namespace-uri()` on a node; use `namespace-uri()` directly when working with nodes rather than `xs:QName` values.
|
||||
- Processors must not confuse a zero-length URI with the empty sequence; the two are distinct results.
|
||||
|
||||
## See also
|
||||
|
||||
- [local-name-from-QName()](../xpath-local-name-from-qname)
|
||||
- [prefix-from-QName()](../xpath-prefix-from-qname)
|
||||
- [resolve-QName()](../xpath-resolve-qname)
|
||||
- [QName()](../xpath-qname)
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: "namespace-uri()"
|
||||
description: "Returns the namespace URI of a node's expanded name, or an empty string if the node has no namespace."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "node function"
|
||||
syntax: "namespace-uri(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`namespace-uri()` returns the namespace URI part of a node's expanded name. For an element `<xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">`, `namespace-uri()` returns `"http://www.w3.org/1999/xhtml"`.
|
||||
|
||||
When called without an argument, it returns the namespace URI of the context node. When called with a node-set, it returns the namespace URI of the first node in document order.
|
||||
|
||||
The function returns `""` (empty string) for:
|
||||
- Nodes with no namespace (unprefixed elements in a document without a default namespace, attributes without a prefix).
|
||||
- Nodes that inherently have no name: text nodes, comment nodes, document nodes.
|
||||
- The `xml:` prefix namespace (`http://www.w3.org/XML/1998/namespace`) is a valid URI that will be returned if the `xml:` prefix is used.
|
||||
|
||||
`namespace-uri()` is essential for writing namespace-portable stylesheets that identify elements by their canonical URI rather than by the potentially varying prefix used in each source document.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node-set | No | The node to inspect. Defaults to the context node. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the namespace URI of the node, or `""` if the node has no namespace.
|
||||
|
||||
## Examples
|
||||
|
||||
### Identify elements by namespace URI
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<xhtml:p xmlns:xhtml="http://www.w3.org/1999/xhtml">XHTML paragraph</xhtml:p>
|
||||
<p>Plain paragraph</p>
|
||||
<svg:rect xmlns:svg="http://www.w3.org/2000/svg" width="100" height="50"/>
|
||||
</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">
|
||||
<info>
|
||||
<xsl:for-each select="*">
|
||||
<node name="{local-name()}" ns="{namespace-uri()}"/>
|
||||
</xsl:for-each>
|
||||
</info>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<info>
|
||||
<node name="p" ns="http://www.w3.org/1999/xhtml"/>
|
||||
<node name="p" ns=""/>
|
||||
<node name="rect" ns="http://www.w3.org/2000/svg"/>
|
||||
</info>
|
||||
```
|
||||
|
||||
### Filter elements from a specific namespace
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<doc>
|
||||
<html:div xmlns:html="http://www.w3.org/1999/xhtml">Section A</html:div>
|
||||
<div>Plain div</div>
|
||||
<html:span xmlns:html="http://www.w3.org/1999/xhtml">Span</html:span>
|
||||
</doc>
|
||||
```
|
||||
|
||||
**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="/doc">
|
||||
<xhtml-only>
|
||||
<xsl:for-each select="*[namespace-uri() = 'http://www.w3.org/1999/xhtml']">
|
||||
<item><xsl:value-of select="."/></item>
|
||||
</xsl:for-each>
|
||||
</xhtml-only>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<xhtml-only>
|
||||
<item>Section A</item>
|
||||
<item>Span</item>
|
||||
</xhtml-only>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- For attributes without a prefix, `namespace-uri()` returns `""` even if they are in scope inside a namespaced element. In XML, unprefixed attributes are not in any namespace.
|
||||
- The `xml:` prefix is predeclared and always maps to `http://www.w3.org/XML/1998/namespace`; `namespace-uri()` on an `xml:lang` attribute returns that URI.
|
||||
- Never rely on `name()` for namespace-aware matching across documents — always use `namespace-uri()` and `local-name()` together.
|
||||
- In XSLT 2.0+, `fn:namespace-uri()` is unchanged. The argument must be zero or one node.
|
||||
|
||||
## See also
|
||||
|
||||
- [local-name()](../xpath-local-name)
|
||||
- [name()](../xpath-name)
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: "nilled()"
|
||||
description: "Returns true if an element node is schema-validated and marked as nilled with xsi:nil=\"true\", otherwise returns false."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "nilled(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`nilled()` returns `xs:boolean` `true` if the argument is an element node that has been schema-validated and has its **nilled property** set — i.e., the element carries `xsi:nil="true"` and its schema type permits nilling.
|
||||
|
||||
For elements that have not been schema-validated, or for non-element nodes, the function returns `false`. If the argument is the empty sequence, the empty sequence is returned.
|
||||
|
||||
In practice, `nilled()` is used with schema-aware processors (such as Saxon-EE) to distinguish a genuinely absent value (`xsi:nil="true"`) from an element that is simply empty.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node()? | No | The node to test. Defaults to the context node. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean?` — `true` if the element is nilled, `false` if it is not, or the empty sequence if the argument is the empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Filter out nilled elements
|
||||
|
||||
**Input XML (schema-validated):**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<employees xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<employee id="1"><name>Alice</name></employee>
|
||||
<employee id="2" xsi:nil="true"/>
|
||||
<employee id="3"><name>Charlie</name></employee>
|
||||
</employees>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/employees">
|
||||
<active-employees>
|
||||
<xsl:copy-of select="employee[not(nilled(.))]"/>
|
||||
</active-employees>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<active-employees>
|
||||
<employee id="1"><name>Alice</name></employee>
|
||||
<employee id="3"><name>Charlie</name></employee>
|
||||
</active-employees>
|
||||
```
|
||||
|
||||
### Report nil status of each element
|
||||
|
||||
**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="/employees">
|
||||
<report>
|
||||
<xsl:for-each select="employee">
|
||||
<entry id="{@id}" nilled="{nilled(.)}"/>
|
||||
</xsl:for-each>
|
||||
</report>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `nilled()` only returns `true` for schema-validated elements with `xsi:nil="true"` and a nillable type in the schema. Without schema validation, it always returns `false`.
|
||||
- For non-schema-aware processing, checking `@xsi:nil = 'true'` directly is a common alternative.
|
||||
- This function is defined in XPath 2.0 and is not available in XSLT 1.0.
|
||||
|
||||
## See also
|
||||
|
||||
- [node-name()](../xpath-node-name)
|
||||
- [base-uri()](../xpath-base-uri)
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: "node-name()"
|
||||
description: "Returns the name of a node as an xs:QName value, capturing both the namespace URI and the local name."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "node function"
|
||||
syntax: "node-name(node?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt2"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`node-name()` returns the name of an element or attribute node as an `xs:QName`. This is the typed equivalent of `name()` or `local-name()`: rather than returning a string, it returns a structured value from which you can extract the namespace URI, local name, and prefix separately.
|
||||
|
||||
For text nodes, comments, and document nodes, the function returns the empty sequence. When called without an argument, the context node is used.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `node` | node()? | No | The node whose name is requested. Defaults to the context node. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:QName?` — the qualified name of the node, or the empty sequence for text, comment, and document nodes.
|
||||
|
||||
## Examples
|
||||
|
||||
### Compare node names using QName equality
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root xmlns:a="http://example.com/a" xmlns:b="http://example.com/b">
|
||||
<a:item>First</a:item>
|
||||
<b:item>Second</b:item>
|
||||
</root>
|
||||
```
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="2.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:a="http://example.com/a">
|
||||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:template match="/root">
|
||||
<matches>
|
||||
<xsl:for-each select="*">
|
||||
<!-- node-name() eq QName() compares namespace-aware -->
|
||||
<match name="{local-name-from-QName(node-name(.))}"
|
||||
ns="{namespace-uri-from-QName(node-name(.))}"/>
|
||||
</xsl:for-each>
|
||||
</matches>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<matches>
|
||||
<match name="item" ns="http://example.com/a"/>
|
||||
<match name="item" ns="http://example.com/b"/>
|
||||
</matches>
|
||||
```
|
||||
|
||||
### Dispatch based on qualified name
|
||||
|
||||
**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"
|
||||
xmlns:a="http://example.com/a">
|
||||
<xsl:output method="text"/>
|
||||
|
||||
<xsl:template match="/root/*">
|
||||
<xsl:choose>
|
||||
<xsl:when test="node-name(.) eq QName('http://example.com/a', 'item')">
|
||||
<xsl:value-of select="concat('Namespace A item: ', ., ' ')"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="concat('Other item: ', ., ' ')"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Use `local-name-from-QName()`, `namespace-uri-from-QName()`, and `prefix-from-QName()` to decompose the returned `xs:QName`.
|
||||
- `node-name()` is namespace-aware; for a simple string name, `name()` or `local-name()` may be sufficient.
|
||||
- The prefix in the returned QName reflects the prefix used in the source document, which may differ from the prefix in the stylesheet.
|
||||
|
||||
## See also
|
||||
|
||||
- [local-name-from-QName()](../xpath-local-name-from-qname)
|
||||
- [namespace-uri-from-QName()](../xpath-namespace-uri-from-qname)
|
||||
- [QName()](../xpath-qname)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
title: "normalize-space()"
|
||||
description: "Strips leading and trailing whitespace from a string and collapses all internal whitespace sequences to a single space character."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "string function"
|
||||
syntax: "normalize-space(string?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`normalize-space()` performs three whitespace normalisation steps on its string argument:
|
||||
|
||||
1. Strips all leading whitespace (spaces, tabs, newlines, carriage returns).
|
||||
2. Strips all trailing whitespace.
|
||||
3. Replaces each internal sequence of one or more whitespace characters with a single space (`U+0020`).
|
||||
|
||||
When called without an argument, it normalises the string value of the context node.
|
||||
|
||||
This function is indispensable when working with XML data that may contain arbitrary indentation or line breaks in element content — for example, multi-line address fields, code-generated XML, or content extracted from mixed-content elements.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string | No | The string to normalise. Defaults to the context node's string value. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the normalised string with collapsed whitespace.
|
||||
|
||||
## Examples
|
||||
|
||||
### Clean up user-entered text
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<contacts>
|
||||
<name> Alice Smith </name>
|
||||
<name>Bob
|
||||
Jones</name>
|
||||
</contacts>
|
||||
```
|
||||
|
||||
**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="/contacts">
|
||||
<clean>
|
||||
<xsl:for-each select="name">
|
||||
<name><xsl:value-of select="normalize-space(.)"/></name>
|
||||
</xsl:for-each>
|
||||
</clean>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<clean>
|
||||
<name>Alice Smith</name>
|
||||
<name>Bob Jones</name>
|
||||
</clean>
|
||||
```
|
||||
|
||||
### Use in a predicate to filter blank elements
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lines>
|
||||
<line>First line</line>
|
||||
<line> </line>
|
||||
<line>Third line</line>
|
||||
<line></line>
|
||||
</lines>
|
||||
```
|
||||
|
||||
**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="/lines">
|
||||
<non-empty>
|
||||
<xsl:for-each select="line[normalize-space(.) != '']">
|
||||
<line><xsl:value-of select="normalize-space(.)"/></line>
|
||||
</xsl:for-each>
|
||||
</non-empty>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<non-empty>
|
||||
<line>First line</line>
|
||||
<line>Third line</line>
|
||||
</non-empty>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `normalize-space('')` returns the empty string `""`.
|
||||
- The characters considered whitespace are: space (`U+0020`), tab (`U+0009`), carriage return (`U+000D`), and line feed (`U+000A`) — the same set as the XML `S` production.
|
||||
- `normalize-space()` does not affect non-whitespace characters; it only collapses runs of whitespace, including mixed sequences of tabs and newlines.
|
||||
- It is often used inside predicates: `element[normalize-space() != '']` selects only elements with non-blank text content.
|
||||
- In XSLT 2.0+, the function is unchanged. For more advanced whitespace handling (such as preserving significant spaces), use `xml:space="preserve"` or the XSLT `normalize-unicode()` function.
|
||||
|
||||
## See also
|
||||
|
||||
- [string()](../xpath-string)
|
||||
- [string-length()](../xpath-string-length)
|
||||
- [translate()](../xpath-translate)
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: "normalize-unicode()"
|
||||
description: "Applies Unicode normalization (NFC, NFD, NFKC, NFKD, or FULLY-NORMALIZED) to a string, ensuring a canonical character representation."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "2.0"
|
||||
versionLabel: "XSLT 2.0"
|
||||
category: "string function"
|
||||
syntax: "normalize-unicode(string, normalization-form?)"
|
||||
tags: ["xslt", "reference", "xslt2", "xpath"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`normalize-unicode()` converts a string to a specified Unicode normalization form. Different normalization forms control whether composed or decomposed character representations are used, and whether compatibility equivalents are collapsed.
|
||||
|
||||
The most common use case is ensuring consistent string comparison when data may come from different systems that represent the same character differently — for example, the letter `é` can be stored as a single precomposed codepoint (U+00E9) or as `e` followed by a combining accent (U+0065 U+0301).
|
||||
|
||||
Normalization forms:
|
||||
|
||||
| Form | Name | Description |
|
||||
|------|------|-------------|
|
||||
| `NFC` | Canonical Decomposition + Canonical Composition | Precomposed form (default, most common) |
|
||||
| `NFD` | Canonical Decomposition | Fully decomposed; base characters followed by combining marks |
|
||||
| `NFKC` | Compatibility Decomposition + Canonical Composition | Collapses compatibility variants (e.g., ligatures, width variants) |
|
||||
| `NFKD` | Compatibility Decomposition | Decomposed compatibility form |
|
||||
| `FULLY-NORMALIZED` | W3C XML extension | NFC with additional normalization of initial combining marks |
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `string` | xs:string? | Yes | The string to normalize. |
|
||||
| `normalization-form` | xs:string | No | One of `NFC`, `NFD`, `NFKC`, `NFKD`, `FULLY-NORMALIZED`. Defaults to `NFC`. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:string` — the input string in the requested normalization form. Returns `""` if `string` is an empty sequence.
|
||||
|
||||
## Examples
|
||||
|
||||
### Normalizing to NFC for consistent comparison
|
||||
|
||||
**Stylesheet:**
|
||||
```xml
|
||||
<?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="/strings">
|
||||
<normalized>
|
||||
<xsl:for-each select="s">
|
||||
<!-- Ensure NFC before comparison or storage -->
|
||||
<s><xsl:value-of select="normalize-unicode(., 'NFC')"/></s>
|
||||
</xsl:for-each>
|
||||
</normalized>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
### Collapsing compatibility variants with NFKC
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data>
|
||||
<!-- Contains fi ligature (U+FB01) and ² superscript (U+00B2) -->
|
||||
<value>file²</value>
|
||||
</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">
|
||||
<result>
|
||||
<!-- NFKC: fi → fi, ² → 2 -->
|
||||
<xsl:value-of select="normalize-unicode(value, 'NFKC')"/>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>file2</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- NFC is the recommended normalization for most XML and web applications; it is the form used in HTML5 and most web APIs.
|
||||
- NFKC is useful for search and indexing where compatibility equivalents should be treated identically (e.g., full-width vs. half-width letters, ligatures).
|
||||
- NFD is mainly useful for low-level text processing or font rendering.
|
||||
- The normalization form argument is case-insensitive; `"nfc"` and `"NFC"` are equivalent.
|
||||
- If the argument is `""` (empty string), the NFC form (default) is applied.
|
||||
|
||||
## See also
|
||||
|
||||
- [upper-case()](../xpath-upper-case)
|
||||
- [lower-case()](../xpath-lower-case)
|
||||
- [codepoints-to-string()](../xpath-codepoints-to-string)
|
||||
- [string-to-codepoints()](../xpath-string-to-codepoints)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: "not()"
|
||||
description: "Returns true if its boolean argument is false, and false if it is true — the logical negation of a boolean expression."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "boolean function"
|
||||
syntax: "not(boolean)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`not()` returns the logical negation of its argument. The argument is first converted to a boolean using the same rules as `boolean()`, and the result is the opposite value.
|
||||
|
||||
It is one of the most frequently used functions in XPath predicates and `xsl:if` conditions, allowing you to express "if this node does not exist", "if this string is empty", or "if this condition does not hold".
|
||||
|
||||
Because `not()` accepts any type and coerces it to boolean, you can negate node-set tests, string emptiness checks, and numeric comparisons in a single, readable expression.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `boolean` | any | Yes | The value to negate. Converted to boolean before negation. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:boolean` — `true` if the argument converts to `false`, `false` if it converts to `true`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Skip elements without a required attribute
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<products>
|
||||
<product id="1" name="Widget" price="9.99"/>
|
||||
<product id="2" name="Gadget"/>
|
||||
<product id="3" name="Doohickey" price="4.49"/>
|
||||
</products>
|
||||
```
|
||||
|
||||
**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="/products">
|
||||
<priced>
|
||||
<xsl:for-each select="product[not(@price)]">
|
||||
<missing id="{@id}"><xsl:value-of select="@name"/></missing>
|
||||
</xsl:for-each>
|
||||
</priced>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<priced>
|
||||
<missing id="2">Gadget</missing>
|
||||
</priced>
|
||||
```
|
||||
|
||||
### Conditional output based on element absence
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<order>
|
||||
<item>Book</item>
|
||||
<item>Pen</item>
|
||||
</order>
|
||||
```
|
||||
|
||||
**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="/order">
|
||||
<result>
|
||||
<xsl:if test="not(discount)">
|
||||
<message>No discount applied.</message>
|
||||
</xsl:if>
|
||||
<xsl:for-each select="item">
|
||||
<line><xsl:value-of select="."/></line>
|
||||
</xsl:for-each>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<message>No discount applied.</message>
|
||||
<line>Book</line>
|
||||
<line>Pen</line>
|
||||
</result>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `not(condition)` is equivalent to writing `condition = false()` but is more idiomatic and concise.
|
||||
- To negate a compound condition, combine `not()` with `and`/`or`: `not(a or b)` means neither `a` nor `b` is true.
|
||||
- `not()` cannot be used as a shorthand for inequality (`!=`). Use `@attr != 'value'` rather than `not(@attr = 'value')` when comparing against multiple nodes, because the semantics differ for node-sets with more than one node.
|
||||
- In XSLT 2.0+ the function works identically; the argument may also be an empty sequence (which converts to `false`, so `not(())` returns `true`).
|
||||
|
||||
## See also
|
||||
|
||||
- [boolean()](../xpath-boolean)
|
||||
- [true()](../xpath-true)
|
||||
- [false()](../xpath-false)
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
title: "number()"
|
||||
description: "Converts a string, boolean, or node-set to a number following XPath 1.0 type-conversion rules, returning NaN if the conversion fails."
|
||||
date: 2026-04-18T00:00:00Z
|
||||
version: "1.0"
|
||||
versionLabel: "XSLT 1.0"
|
||||
category: "numeric function"
|
||||
syntax: "number(object?)"
|
||||
tags: ["xslt", "reference", "xpath", "xslt1"]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
`number()` converts its argument to a number using XPath 1.0 numeric conversion rules:
|
||||
|
||||
- **String:** the string is stripped of leading and trailing whitespace and then parsed as a decimal number. If it cannot be parsed, the result is `NaN`.
|
||||
- **Boolean:** `true` converts to `1`, `false` converts to `0`.
|
||||
- **Node-set:** the node-set is first converted to its string value (same as calling `string()` on it), and then that string is converted to a number.
|
||||
- **Number:** returned unchanged.
|
||||
|
||||
When called with no arguments, `number()` converts the string value of the context node.
|
||||
|
||||
`number()` is essential when you need to perform arithmetic on element content or attribute values that XPath does not automatically treat as numbers, or when you want to explicitly coerce a value and test for `NaN` before proceeding.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `object` | any | No | Value to convert. Defaults to the context node's string value when omitted. |
|
||||
|
||||
## Return value
|
||||
|
||||
`xs:double` — the numeric value, or `NaN` if conversion fails.
|
||||
|
||||
## Examples
|
||||
|
||||
### Arithmetic on element content
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<prices>
|
||||
<price>12.50</price>
|
||||
<price>7.99</price>
|
||||
<price>3.00</price>
|
||||
</prices>
|
||||
```
|
||||
|
||||
**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="/prices">
|
||||
<result>
|
||||
<total><xsl:value-of select="sum(price)"/></total>
|
||||
<first-doubled><xsl:value-of select="number(price[1]) * 2"/></first-doubled>
|
||||
</result>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<result>
|
||||
<total>23.49</total>
|
||||
<first-doubled>25</first-doubled>
|
||||
</result>
|
||||
```
|
||||
|
||||
### Guard against NaN before output
|
||||
|
||||
**Input XML:**
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<data>
|
||||
<value>42</value>
|
||||
<value>N/A</value>
|
||||
</data>
|
||||
```
|
||||
|
||||
**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="/data">
|
||||
<results>
|
||||
<xsl:for-each select="value">
|
||||
<xsl:variable name="n" select="number(.)"/>
|
||||
<item>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$n = $n">
|
||||
<xsl:value-of select="$n"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>invalid</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</item>
|
||||
</xsl:for-each>
|
||||
</results>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```xml
|
||||
<results>
|
||||
<item>42</item>
|
||||
<item>invalid</item>
|
||||
</results>
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The XPath 1.0 idiom to detect `NaN` is `$n != $n` (or equivalently `not($n = $n)`), because `NaN` is the only value not equal to itself.
|
||||
- Whitespace around numbers in element content is ignored: `number(' 3.14 ')` returns `3.14`.
|
||||
- Strings like `"Infinity"` and `"-Infinity"` are recognised by some processors as the numeric infinity values, but this is implementation-defined in XPath 1.0.
|
||||
- In XSLT 2.0+, `xs:double()`, `xs:integer()`, and `xs:decimal()` provide schema-aware type casting and raise errors on invalid input instead of returning `NaN`.
|
||||
|
||||
## See also
|
||||
|
||||
- [floor()](../xpath-floor)
|
||||
- [ceiling()](../xpath-ceiling)
|
||||
- [round()](../xpath-round)
|
||||
- [format-number()](../xpath-format-number)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user