The xsl:merge
instruction allows a sorted sequence of items to be
constructed by merging several input sequences. Each
input sequence must have a merge key (one or more
atomic values that can be computed as a function of the items in the sequence); the
input sequence must either already be sorted on the value of
its merge keys, or pre-sorting on these values must be requested.
The merge keys for the different input sequences must be compatible in the sense that key
values from an item in one sequence are always comparable with key values from an
item in a different sequence.
For example, if two log files contain details of events sorted by date and time, then
the xsl:merge
instruction can be used to combine these into a single
sequence that is also sorted by date and time.
The data written to the output sequence can be computed in an arbitrary way from the data in the input sequences, provided it follows the ordering of the input sequences.
The xsl:merge
instruction can be used to merge several sequences of
items that all have the same structure (more precisely, sequences whose merge keys
are
computed in the same way): for example, log files created by the same application
running on different machines in a server farm. Alternatively,
xsl:merge
can be used to merge sequences that have different
structure (sequences whose merge keys are computed in different ways), provided that
the
computed merge keys are compatible: an example might be two log files created by
different applications, using different XML vocabularies, that both contain timestamped
events but represent the timestamp in different ways. The
xsl:merge-source
element represents a set
of input sequences that follow common rules, including the rules for
computing the merge key. The xsl:merge
operation may take any number of
xsl:merge-source
elements representing different rules for input sequences, and each xsl:merge-source
element may describe any number (zero or more) of input sequences. The number of input
sequences to the merging operation is thus fixed only at the
time the xsl:merge
instruction is evaluated, and
may vary from one evaluation to another.
The following examples illustrate some of the possibilities. The detailed explanation of the constructs used follows later in this section.
This example takes as input a homogeneous collection of XML log files each of which
contains a sorted sequence of event
elements with a
timestamp
attribute validated as an instance of
xs:dateTime
. It merges the events from the input files into a single
sorted output file.
<xsl:result-document href="merged-events.xml"> <events> <xsl:merge> <xsl:merge-source for-each-source="uri-collection('log-files')" select="events/event"> <xsl:merge-key select="@timestamp"/> </xsl:merge-source> <xsl:merge-action> <xsl:copy-of select="current-merge-group()"/> </xsl:merge-action> </xsl:merge> </events> </xsl:result-document>
The example assumes that there are several input files each
of which has a structure similar to the following, in which the
timestamp
attribute has a typed value that is an instance of
xs:dateTime
:
<events> <event timestamp="2009-08-20T12:01:01Z">Transaction T1234 started</event> <event timestamp="2009-08-20T12:01:08Z">Transaction T1235 started</event> <event timestamp="2009-08-20T12:01:12Z">Transaction T1235 ended</event> <event timestamp="2009-08-20T12:01:15Z">Transaction T1234 ended</event> </events>
The output file will have the same structure, and will contain copies of all the
event
elements from all of the input files, in sorted order. Note that multiple events with the same timestamp can occur
either within a single file or across multiple files: the order of appearance of
these events in the output file corresponds to the order of the log files within
the collection (which might or might not be predictable, depending on the
implementation).
This example takes as input two log files with different structure, producing a single merged output in which the entries have a common structure:
<xsl:result-document href="merged-events.xml"> <events> <xsl:merge> <xsl:merge-source select="doc('log-file-1.xml')/events/event"> <xsl:merge-key select="@timestamp"/> </xsl:merge-source> <xsl:merge-source select="doc('log-files-2.xml')/log/day/record"> <xsl:merge-key select="dateTime(../@date, time)"/> </xsl:merge-source> <xsl:merge-action> <xsl:apply-templates select="current-merge-group()" mode="standardize-log-entry"/> </xsl:merge-action> </xsl:merge> </events> </xsl:result-document>
Here the first input file has a structure similar to that shown in the previous example, while the second input has a different structure, of the form:
<log> <day date="2009-08-20"> <record> <time>12:01:09-05:00</time> <message>Temperature 15.4C</message> </record> <record> <time>12:03:00-05:00</time> <message>Temperature 18.2C</message> </record> </day> </log>
The templates in mode standardize-log-entry
convert the log entries to a
common output format, for example:
<xsl:template match="event" mode="standardize-log-entry" as="schema-element(event)"> <xsl:copy-of select="." validation="preserve"/> </xsl:template> <xsl:template match="record" mode="standardize-log-entry" as="schema-element(event)"> <event timestamp="{dateTime(../@date, time)}" xsl:validation="strict"> <xsl:value-of select="message"/> </event> </xsl:template>
Note:
The xsl:merge
instruction is designed to enable streaming of data,
so that there is no need to allocate memory to hold the input sequences. However, it can also be used in cases where streamed
processing is not possible, for example when the input needs to be
sorted.
[Definition: A merge
source definition is the definition of one kind of input to the merge
operation. It selects zero or more merge
input sequences, and it includes a merge key specification to define
how the merge key
values are computed for each such merge input
sequence.] A merge source definition corresponds to an
xsl:merge-source
element in the stylesheet.
[Definition: A merge input sequence is an arbitrary sequenceDM30 of items which is already sorted according to the merge key specification for the corresponding merge source definition.]
[Definition: A merge
key specification consists of one or more adjacent
xsl:merge-key
elements which together define how the merge input sequences selected by a
merge source definition are
sorted. Each xsl:merge-key
element defines one merge key component.] For
example, a merge key specification for a log file might specify two merge key
components, date
and time
.
[Definition: A merge key
component specifies one component of a merge key specification; it
corresponds to a single xsl:merge-key
element in the
stylesheet.]
[Definition: For each item in a merge input sequence, a value is computed for each merge key component within the merge key specification. The value computed for an item by using the Nth merge key component is referred to as the Nth merge key value of that item.]
[Definition: The ordered collection of merge key values computed for one item in a merge input sequence (one for each merge key component within the merge key specification) is referred to as a composite merge key value.]
[Definition: A merge
activation is a single evaluation of the sequence constructor contained
within the xsl:merge-action
element, which occurs once for each
distinct composite merge key
value.]
xsl:merge
Instruction<!-- Category: instruction -->
<xsl:merge>
<!-- Content: (xsl:merge-source+, xsl:merge-action, xsl:fallback*) -->
</xsl:merge>
The effect of the xsl:merge
instruction is to produce a sorted
result sequence from a number of input sequences.
The input sequences to the merge operation are defined by the
xsl:merge-source
child elements, as described in the next
section.
The sequence constructor contained in the
xsl:merge-action
element is evaluated once for each distinct
composite merge key value to form a partial result sequence.
The result of the xsl:merge
instruction is the concatenation of
these partial result sequences. For example, the action might be to copy the items
from all the input sequences to the result sequence without change; or it might be
to
select the items from one input sequence in preference to the others. In the general
case, the items in the partial result sequence are produced by an arbitrary
computation that has access to the items (from the various input sequences) that
share the same value for the composite merge key.
The xsl:merge-source
and
xsl:merge-action
elements are described in the following
sections.
Any xsl:fallback
children of the xsl:merge
instruction are ignored by an XSLT 3.0 processor, but are used by an XSLT 1.0 or XSLT
2.0 processor to perform fallback processing.
Note:
An xsl:merge
instruction that has no input sequences returns an
empty sequence. An xsl:merge
instruction with a single input
sequence performs processing that is very similar in concept to
xsl:for-each-group
with the group-adjacent
attribute, except that it requires the input to be sorted on the grouping key.
<xsl:merge-source
name? = ncname
for-each-item? = expression
for-each-source? = expression
select = expression
streamable? = boolean
use-accumulators? = tokens
sort-before-merge? = boolean
validation? = "strict" | "lax" | "preserve" | "strip"
type? = eqname >
<!-- Content: xsl:merge-key+ -->
</xsl:merge-source>
Each xsl:merge-source
element defines one or more merge input sequences.
The name
attribute provides a means of
distinguishing items from different merge sources within the
xsl:merge-action
instructions. If the name
attribute
is present on an xsl:merge-source
element, then it must not be equal
to the name
attribute of any sibling xsl:merge-source
element. If the name
attribute is absent, then an implementation-dependent name, different from all explicitly specified
names, is allocated to the merge source.
[ERR XTSE3195] If the for-each-item
is present then the
for-each-source
, use-accumulators
, and streamable
attributes
must both be absent. If the use-accumulators
attribute is present
then the for-each-source
attribute must be present. If the
for-each-source
attribute is present then the
for-each-item
attribute must be absent.
The use-accumulators
attribute defines the
set of accumulators that are applicable to the streamed document, as explained in
18.2.2 Applicability of Accumulators.
If neither of
for-each-item
and for-each-source
is
present, the xsl:merge-source
element defines a single
merge input sequence. This sequence is the result of evaluating the expression in
the
select
attribute. This is evaluated using the dynamic context of the
containing xsl:merge
instruction. This sequence will be merged with
the sequences defined by other xsl:merge-source
elements, if
present.
When the for-each-item
attribute is present, the xsl:merge-source
element defines a
collection of merge input sequences. The selection of items in these input sequences
is a two-stage process: the for-each-item
attribute of the
xsl:merge-source
element is an expression that selects a sequence
of anchor items, and for each anchor item, the select
attribute is evaluated to select the items that make up one merge input sequence.
The
for-each-item
expression is evaluated with
the dynamic context of the containing xsl:merge
instruction, while
the select
attribute is evaluated with the focus for the evaluation as follows:
The context item is the anchor item
The context position is the position of the anchor item within the sequence of anchor items
The context size is the number of anchor items.
When the for-each-source
attribute is
present, its value must be an expression that returns a sequence of URIs.
The expression is evaluated with the same
dynamic context as the containing xsl:merge
instruction. The
expected type of the expression is xs:string*
, and the actual result of
the expression is converted to this type using the function conversion rules. Each of these URIs is used to obtain a
document node. Each must be a valid URI reference. If it is an
absolute URI reference, it is used as is; if it is a relative URI reference, it is
made absolute by resolving it against the base URI of the
xsl:merge-source
element. The process of obtaining a document
node given a URI is the same as for the doc
FO30 function, and may trigger the same error conditions.
However, unlike the doc
FO30 function, the
xsl:merge
instruction offers no guarantee that the resulting
document will be stable (that is, that multiple calls specifying the same URI will
return the same document). The resulting document nodes act as the anchor
items. These anchor items are then used in the same way as a sequence of
anchor items selected directly using the for-each-item
attribute:
in particular, the focus is
determined in the same way.
Note:
Examples of expressions that return a sequence of URIs are:
for-each-source="'inputA.xml', 'inputB.xml'"
for-each-source="(1 to $N) ! ('input' || $N || '.xml')"
for-each-source="uri-collection('input/dir/')
Relative URIs are resolved relative to the base URI of the
xsl:merge-source
element.
The attributes validation
and
type
are used to control schema validation of documents read by
virtue of their appearance in the result of the for-each-source
expression. These attributes are mutually exclusive [see ERR XTSE1505]. The rules are the same as for an xsl:source-document
instruction specifying streamable="yes"
.
If the for-each-source
attribute is absent, then the
validation
and type
attributes must
both be absent.
If the sort-before-merge
attribute is absent or has
the value no
, then each input sequence must already
be in the correct order for merging (a dynamic error occurs if it is not). If the
attribute is present with the value yes
, then each input sequence will
first be sorted to ensure that it is in the correct order.
The following xsl:merge-source
element selects two anchor items
(the root nodes of two documents), and for each of these it selects an input
sequence consisting of selected event
elements within the relevant
document.
<xsl:merge-source for-each-source="'log-A.xml', 'log-B.xml'" streamable="yes" select="events/event"> <xsl:merge-key select="@timestamp" order="ascending"/> </xsl:merge-source>
This example can be extended to merge any number of input documents with the same structure:
<xsl:merge-source for-each-source="uri-collection('log-collection')" streamable="yes" select="events/event"> <xsl:merge-key select="@time" order="ascending"/> </xsl:merge-source>
In both the above examples the anchor items are document nodes, and the items in the input sequence are elements within the document that is rooted at this node. This is a common usage pattern, but by no means the only way in which the construct can be used.
The number of anchor items selected by an xsl:merge-source
element,
and therefore the number of input sequences, is variable, but the input sequences
selected by one xsl:merge-source
element must all use the same
expressions to select the items in the input sequence and to compute their merge
keys. If different expressions are needed for different input sequences, then
multiple xsl:merge-source
elements can be used.
The following code merges two log files having different internal structure:
<xsl:merge-source for-each-source="'event-log.xml'" streamable="yes" select="/*/event"> <xsl:merge-key select="@timestamp"/> </xsl:merge-source> <xsl:merge-source for-each-source="'error-log.xml'" streamable="yes" select="/*/error"> <xsl:merge-key select="dateTime(@date, @time)"/> </xsl:merge-source>
Although the merge keys are computed in different ways for the two input
sequences, the keys must be compatible across the two sequences: in this case they
are both atomic values of type xs:dateTime
.
In the common case where there is only one input sequence of a particular kind, the
for-each-item
attribute of
xsl:merge-source
may be omitted; the select
expression is then evaluated relative to the focus
of the xsl:merge
instruction itself.
Where one or more of the inputs to the merging process is not pre-sorted, a sort
can be requested using the sort-before-merge
attribute. For
example:
<xsl:merge-source select="doc('event-log.xml')/*/event"> <xsl:merge-key select="@timestamp"/> </xsl:merge-source> <xsl:merge-source select="doc('error-log.xml')//error" sort-before-merge="yes"> <xsl:merge-key select="dateTime(current-date(), @time)"/> </xsl:merge-source>
[ERR XTSE3190] It is a static error if two sibling
xsl:merge-source
elements have the same name.
Any input to a merging operation, provided it is selected
by means of the xsl:merge-source
element with a
for-each-source
attribute, may be designated as streamable by
including the attribute streamable="yes"
on the
xsl:merge-source
element.
When streamable="yes"
is specified on an
xsl:merge-source
element, then (whether or not streamed
processing is actually used, and whether or not the processor supports streaming)
the
expression appearing in the select
attribute is implicitly used as the
argument of a call on the snapshot
function, which means that
merge keys for each selected node are computed with reference to this snapshot, and
the current-merge-group
function, when used within the
xsl:merge-action
sequence constructor, delivers snapshots of the
selected nodes.
Note:
There are therefore no constraints on the navigation
that may be performed in computing the merge key, or in the course of evaluating
the xsl:merge-action
body. An attempt to navigate outside the
portion of the source document delivered by the snapshot
function will typically not cause an error, but will return empty results.
There is no
rule to prevent the select
expression returning atomic values, or grounded nodes from a
different source document, or newly constructed nodes, but they are still
processed using the snapshot
function.
Because the snapshot
copies
accumulator values as described in 18.2.10 Copying Accumulator Values, the
functions accumulator-before
and
accumulator-after
may be used to gain access to
information that is not directly available in the nodes that are present within
each snapshot (for example, information in a header section of the merge input
document).
An xsl:merge-source
element is guaranteed-streamable if it satisfies all the following conditions:
The xsl:merge-source
element has the
attribute value streamable="yes"
;
The for-each-source
attribute is
present on that xsl:merge-source
element;
The expression in the select
attribute of that
xsl:merge-source
element, assessed with a
context posture of striding
and a context item type of U{document-node()},
has striding or grounded posture
and motionless or consuming sweep;
The sort-before-merge
attribute of that
xsl:merge-source
element is either absent or takes its
default value of no
.
Specifying streamable="yes"
on an
xsl:merge-source
element declares an intent that the
xsl:merge
instruction should be streamable with respect to that particular source, either because it is guaranteed-streamable, or because it takes advantage of
streamability extensions offered by a particular processor. The
consequences of declaring the instruction to be streamable when it is not in fact
guaranteed streamable depend on the conformance level of the processor, and are
explained in 19.10 Streamability Guarantees.
The following example merges two log files, processing each of them using streaming.
<events> <xsl:merge> <xsl:merge-source for-each-source="'log-file-1.xml'" select="/events/event" streamable="yes"> <xsl:merge-key select="@timestamp"/> </xsl:merge-source> <xsl:merge-source for-each-source="'log-files-2.xml'" select="/log/day/record" streamable="yes"> <xsl:merge-key select="dateTime(../@date, time)"/> </xsl:merge-source> <xsl:merge-action> <events time="{current-merge-key()}"> <xsl:copy-of select="current-merge-group()"/> </events> </xsl:merge-action> </xsl:merge> </events>
Note that the merge key for the second merge source includes data from a child
element of the selected element and also from an attribute of the parent element.
This works because of the merge key is evaluated on the result of implicitly applying
the snapshot
function.
The following example merges two log files, one in text format and one in XML format.
<events> <xsl:merge> <xsl:merge-source name="fax" select="unparsed-text-lines('fax-log.txt')"> <xsl:merge-key select="xs:dateTime(substring-before(., ' '))"/> </xsl:merge-source> <xsl:merge-source name="mail" for-each-source="'mail-log.xml'" select="/log/day/message" streamable="yes"> <xsl:merge-key select="dateTime(../@date, @time)"/> </xsl:merge-source> <xsl:merge-action> <messages at="{current-merge-key()}"> <xsl:where-populated> <fax> <xsl:for-each select="current-merge-group('fax')"> <message xsl:expand-text="true">{ substring-after(., ' ') }</message> </xsl:for-each> </fax> <mail> <xsl:sequence select="current-merge-group('mail')/*"/> </mail> </xsl:where-populated> </messages> </xsl:merge-action> </xsl:merge> </events>
The keys on which the input sequences are sorted are referred to as merge keys. If
the attribute sort-before-merge
has the value yes
, the
input sequences will be sorted into the correct sequence before the merge operation
takes place (alternatively, the processor may use an algorithm
that has the same effect as sorting followed by merging). If the attribute is absent
or has the value no
, then the input sequences must
already be in the correct order.
The merge key for each type of input sequence (that is, for each
xsl:merge-source
element) is defined by a sequence of
xsl:merge-key
element children of the
xsl:merge-source
element. Each xsl:merge-key
element defines one merge key component. The syntax and semantics of an
xsl:merge-key
element are closely based on the rules for the
xsl:sort
element (the only exception being the absence of the
stable
attribute); the difference is that
xsl:merge-key
elements do not cause a sort to take place, they
merely declare the existing sort order of the input sequence.
<xsl:merge-key
select? = expression
lang? = { language }
order? = { "ascending" | "descending" }
collation? = { uri }
case-order? = { "upper-first" | "lower-first" }
data-type? = { "text" | "number" | eqname } >
<!-- Content: sequence-constructor -->
</xsl:merge-key>
The select
attribute and the contained sequence constructor are mutually
exclusive:
[ERR XTSE3200] It is a static error if an
xsl:merge-key
element with a select
attribute
has non-empty content.
The value of Nth merge key value of an item
J in a merge input
sequence
S is the result of the expression in the select
attribute of
the Nth xsl:merge-key
child of the corresponding
xsl:merge-source
element, or in the absence of the
select
attribute, the result of the contained sequence constructor. This is evaluated with a singleton focus based on J, or, if
streamable=yes
is specified on the xsl:merge-source
,
a singleton focus based on a snapshot
of
J (see 15.4 Streamable Merging).
Note:
This means that position()
and last()
return 1 (one).
This differs from the way xsl:sort
keys are evaluated, where
position()
is the position in the unsorted sequence, and
last()
is the size of the unsorted sequence.
The effect of the xsl:merge-key
elements is defined in terms of the
rules for an equivalent sequence of xsl:sort
elements: if the rules
for sorting (see 13.1.1 The Sorting Process) with stable="yes"
would place an item A before an item B in the sorted sequence produced by the sorting
process, then A must precede B in the input sequence to the
merging process.
The merge keys of the various input sequences to a merge operation must be compatible
with each other, since the merge operation will decide the ordering of the result
sequence by comparing merge key values across input sequences. This means that across
all the xsl:merge-source
children of an xsl:merge
instruction:
Each xsl:merge-source
element must have the
same number of xsl:merge-key
child elements; let this number
be N.
For each integer J in 1..N, consider the set of
xsl:merge-key
elements that are in position J
among the xsl:merge-key
children of their parent
xsl:merge-source
element. All the
xsl:merge-key
elements in this set must
have the same effective value for
their lang
, order
, collation
,
case-order
, and data-type
attributes, where having
the same effective value in this case means that either both attributes must be
absent, or both must be present and evaluate to the same value; and in addition
in the case of collation
the absolute URI must be the same after
resolving against the base URI.
If any of the attributes lang
, order
,
collation
, case-order
, or data-type
are
attribute value templates,
then their effective values are evaluated
using the focus of the containing
xsl:merge
instruction.
[ERR XTSE2200] It is a static error if the number of
xsl:merge-key
children of a
xsl:merge-source
element is not equal to the number of
xsl:merge-key
children of another
xsl:merge-source
child of the same
xsl:merge
instruction.
[ERR XTDE2210] It is a dynamic
error if there are two xsl:merge-key
elements
that occupy corresponding positions among the xsl:merge-key
children of two different xsl:merge-source
elements and that
have differing effective values for
any of the attributes lang
, order
,
collation
, case-order
, or data-type
.
Values are considered to differ if the attribute is present on one element and
not on the other, or if it is present on both elements with effective values that are not equal to
each other. In the case of the collation
attribute, the values are
compared as absolute URIs after resolving against the base URI. The error
may be reported statically if it is detected
statically.
[ERR XTDE2220] It is a dynamic error if any input
sequence to an xsl:merge
instruction contains two items that
are not correctly sorted according to the merge key values defined on the
xsl:merge-key
children of the corresponding
xsl:merge-source
element, when compared using the collation
rules defined by the attributes of the corresponding
xsl:merge-key
children of the xsl:merge
instruction, unless the attribute sort-before-merge
is present
with the value yes
.
[ERR XTTE2230] It is a type error if some item selected
by a particular merge key in one input sequence is not comparable using the
XPath le
operator with some item selected by the corresponding
sort key in another input sequence.
During processing of an xsl:merge
instruction, two additional values
are available within the dynamic context:
[Definition: The
current merge group is a map. During
evaluation of an xsl:merge
instruction, as each group of
items with equal composite merge
key values is processed, the current merge group is set to a
map whose keys are the names of the various merge sources, and whose
associated values are the items from each merge source having the relevant
composite merge key value.]
[Definition: The current
merge key is a sequence of atomic values. During evaluation of an
xsl:merge
instruction, as each group of items with equal
composite merge key
values is processed, the current merge key is set to the
composite merge key value that these items have in common. ]
These values are made available through the functions
current-merge-group
and
current-merge-key
.
The current merge group and current merge key are available within the sequence
constructor contained by an xsl:merge-action
element. The values are initially
absent during the evaluation of global variables and stylesheet parameters,
during the evaluation of the use
attribute or contained sequence constructor of
xsl:key
, and during the evaluation of the initial-value
attribute of
xsl:accumulator
and the select
attribute of contained sequence constructor of
xsl:accumulator-rule
. All invocation constructs
set the current merge group and current merge key to absent.
Note:
Taken together, these rules mean that any invocation of
current-merge-group
or current-merge-key
that is not lexically scoped by an
xsl:merge-action
element will raise a dynamic error.
When an inner xsl:merge
instruction is lexically nested within the
xsl:merge-action
element of an outer xsl:merge
instruction, any use of
current-merge-group
or current-merge-key
that appears within the
xsl:merge-action
of the inner xsl:merge
instruction is a reference to the
current merge group or current merge key of the inner
xsl:merge
instruction, while any such
reference that appears within the outer xsl:merge-action
element, but not
within the inner xsl:merge-action
, is a reference to the current merge group or current merge key
of the outer xsl:merge
instruction. This means, for example, that a
reference to the current merge group of the outer xsl:merge
can appear in the
select
attribute of an xsl:merge-source
child of the inner xsl:merge
.
On completion of the evaluation of the xsl:merge-action
sequence constructor, the current merge group
and current merge key revert to their previous values.
Returns the group of items currently being processed by an xsl:merge
instruction.
fn:current-merge-group
($source
as
xs:string
) as
item()*
This function is deterministicFO30, context-dependentFO30, and focus-independentFO30.
The current merge group is bound during evaluation of the
xsl:merge-action
child of an xsl:merge
instruction.
If no xsl:merge-action
is being
evaluated, then the current merge group is absent, in which case the
function raises a dynamic error (see below).
The current merge group (if not absent) is a map. It contains the set of items, from all merge inputs, that share a common value for
the merge key. This is structured as a map so that the items from each merge source
can
be identified. The key in the map is the value of the name
attribute of the
corresponding xsl:merge-source
element (or an invented name, in its
absence), and the associated value is the set of items contributed by that merge
group.
The map itself is not made visible, but this function returns values derived from the map. Specifically, if the map is denoted by $G:
The single-argument form of this function returns the value of the expression
if (map:contains($source)) then $G($source) else error()
.
Informally, if there is an xsl:merge-source
element whose
name
attribute matches $source
, the function returns
the items in the current merge group that are contributed by this merge source;
otherwise it raises a dynamic error (see below).
The zero-argument form of the function returns the value of the expression
sort(map:keys($G))!$G(.)
, where the sort()
function
sorts the names of xsl:merge-source
elements into the document
order of the xsl:merge-source
elements in the stylesheet.
Informally, it returns all the items in the current merge group regardless of
which merge source they derive from.
Within the current merge group, the ordering of items from the input sequences is as follows, in major-to-minor order:
Items are first ordered by the xsl:merge-source
element that
defined the input sequence from which the item was taken; items from
xsl:merge-source
A precede items from xsl:merge-source
B if A precedes B in document order within the
stylesheet.
Items from different input sequences selected by the same
xsl:merge-source
element are then ordered based on the order
of the anchor items in the sequence selected by evaluating the select
attribute of the xsl:merge-source
element.
Finally, duplicate items from the same input sequence retain their order from the input sequence.
Duplicates are not eliminated: for example, if the same node is selected in more than one input sequence, it may appear twice in the current merge group.
[ERR XTSE3470] It is a static error if the
current-merge-group
function is used within a pattern.
[ERR XTDE3480] It is a dynamic error if the
current-merge-group
function is used when the current
merge group is absent. The error
may be reported statically if it can be detected
statically.
[ERR XTDE3490] It is a dynamic error if the
$source
argument of the current-merge-group
function does not match the name
attribute of any
xsl:merge-source
element for the current merge operation. The
error may be reported statically if it can be detected
statically.
Because the current merge group is cleared by function calls and
template calls, the current-merge-group
function only has useful
effect when the call appears as a descendant of an xsl:merge-action
element.
If an xsl:merge-source
element has no name
attribute, then
it is not possible to discover the items in the current merge group that derive
specifically from that source, but these items will still be present in the current
merge group, and will be included in the result when the function is called with no
arguments.
Like other XSLT extensions to the dynamic evaluation context, the current merge group is not retained as part of the closure of a function
value. This means that the expression current-merge-group#0
is valid and
returns a function value, but any invocation of this function will fail with a dynamic
error [see ERR XTDE3480].
Returns the merge key of the
merge group currently being processed using the
xsl:merge
instruction.
This function is deterministicFO30, context-dependentFO30, and focus-independentFO30.
The evaluation context for XPath expressions includes a component called the current merge key, which is a sequence of atomic values. The current merge key is the composite merge key value shared in common by all the items within the current merge group.
The function current-merge-key
returns the current merge key.
While the xsl:merge-action
child of an
xsl:merge
instruction is being evaluated, the current merge key will be a single atomic
value if there is a single merge key, or a sequence of atomic values if there are
multiple merge keys.
At other times, the current merge key will be absent.
The merge keys of
all items in a group are not necessarily identical. For example, one might be an
xs:float
while another is a numerically equal
xs:decimal
. The current-merge-key
function returns the merge key of the
first item in the group, after atomization and
casting of xs:untypedAtomic
values to xs:string
.
[ERR XTSE3500] It is a static error if the
current-merge-key
function is used within a pattern.
[ERR XTDE3510] It is a dynamic error if the
current-merge-key
function is used when the current
merge key is absent, or when it is invoked
in the course of evaluating a pattern. The error may be
reported statically if it can be detected statically.
Like other XSLT extensions to the dynamic evaluation context, the current merge key is not retained as part of the closure of a function
value. This means that the expression current-merge-key#0
is valid and
returns a function value, but any invocation of this function will fail with a dynamic
error [see ERR XTDE3510].
xsl:merge-action
ElementThe xsl:merge-action
child of an xsl:merge
instruction defines the processing to be applied for each distinct composite merge key value found in the input sequences to the
xsl:merge
instruction.
<xsl:merge-action>
<!-- Content: sequence-constructor -->
</xsl:merge-action>
The merge key values for each item in an input sequence are calculated based on the
corresponding xsl:merge-key
elements, in the same way as sort key values are calculated using a sequence
of xsl:sort
elements (see 13.1.1 The Sorting Process). If
several items from the same or from different input sequences have the same values
for all their merge keys (comparing pairwise), then they are considered to form a
group. The sequence constructor contained in the xsl:merge-action
element is evaluated once for each such group of items, and the result of the
xsl:merge
instruction is the concatenation of the results
obtained by processing each group in turn.
The groups are processed one by one, based on the values of
the merge keys for the group. If group G has a set of merge
key values M, while group H has a set of merge key values
N, then in the result of the xsl:merge
instruction,
the result of processing group G will precede the result of processing
H if and only if M precedes N in the sort order
defined by the lang
, order
, collation
,
case-order
, and data-type
attributes of the merge key
definitions.
Generally, two sets of merge key values are distinct if any corresponding items in
the two sets of values do not compare equal under the rules for the XPath
eq
operator, under the collating rules for the corresponding merge
key definition. In rare cases, when considering more than two sets of merge key
values, ambiguities may arise because of the non-transitivity of the eq
operator when applied across different numeric types. In this situation, the
partitioning of items into sets having distinct key values is handled in the same
way
as for xsl:for-each-group
(see 14.5 Non-Transitivity),
and is to some extent implementation-dependent.
The focus for evaluation of the sequence
constructor contained in the xsl:merge-action
element is as
follows:
The context item is the first item in
the group being processed, that is
current-merge-group()[1]
The context position is the
position of the current group within the sequence of groups (so the first
evaluation of xsl:merge-action
has position()=1
,
the second has position()=2
, and so on).
The context size is as follows:
If any of the xsl:merge-source
elements within the xsl:merge
instruction specifies
streamable="yes"
(explicitly or implicitly), then absent.
Note:
This means that within the xsl:merge-action
of a streamable xsl:merge
,
calling last()
throws error [ERR XPDY0002] XP30.
Otherwise, the number of groups, that is, the number of distinct sets of merge key values.
Consider a situation where there are two merge sources, named "master"
and
"update"
; the master source identifies a single merge input file (the master
file), while the update source identifies a set of N update files,
perhaps one for each day of the week. The required logic is that if a merge key is
present only in the master file, then the corresponding item should be copied to
the output; if it is present in a single update file then that item replaces the
corresponding item from the master file; if it is present in several update files,
then an error is raised. This can be achieved as follows:
<xsl:merge> <xsl:merge-source name="master" for-each-source="'master.xml'" streamable="yes" select="/events/event"> <xsl:merge-key select="@key"/> </xsl:merge-source> <xsl:merge-source name="updates" for-each-source="uri-collection('updates')" streamable="yes" select="/events/event-change"> <xsl:merge-key select="@affected-key"/> </xsl:merge-source> <xsl:merge-action> <xsl:choose> <xsl:when test="empty(current-merge-group('master'))"> <xsl:message> Error: update is present with no matching master record! </xsl:message> </xsl:when> <xsl:when test="empty(current-merge-group('updates'))"> <xsl:copy-of select="current-merge-group('master')"/> </xsl:when> <xsl:when test="count(current-merge-group('updates')) = 1"> <xsl:copy-of select="current-merge-group('updates')"/> </xsl:when> <xsl:otherwise> <xsl:message> Conflict: multiple updates for the same master record! </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:merge-action> </xsl:merge>
Some words of explanation:
Error messages are produced if there is an update element whose key does not correspond to any element in the master source, or if there is more than one update element corresponding to the same master element.
In the absence of errors, if there is a single update element then it is copied to the output; if there is none, then the master element is copied.
Previous sections introduced examples designed to illustrate some specific features
of the xsl:merge
instruction. This section provides some further
examples to illustrate different ways in which the instruction can be used.
This example applies transactions from a transaction file to a master file. Records in the master file for which there is no corresponding transaction are copied unchanged. The transaction file contains instructions to delete, replace, or insert records identified by an ID value. The master file is known to be sorted on the ID value; the transaction file is unsorted.
Master file document structure:
<data> <record ID="A0001">...</record> <record ID="A0002">...</record> <record ID="A0003">...</record> </data>
Transaction file document structure:
<transactions> <update record="A0004" action="insert">...</update> <update record="A0002" action="delete"/> <update record="A0003" action="replace">...</update> </transactions>
Solution:
<xsl:merge> <xsl:merge-source name="master" select="doc('master.xml')/data/record"> <xsl:merge-key select="@ID"/> </xsl:merge-source> <xsl:merge-source name="updates" sort-before-merge="yes" select="doc('transactions.xml')/transactions/update"> <xsl:merge-key select="@record"/> </xsl:merge-source> <xsl:merge-action> <xsl:choose> <xsl:when test="empty(current-merge-group('updates'))"> <xsl:copy-of select="current-merge-group('master')"/> </xsl:when> <xsl:when test="current-merge-group('updates')/@action=('insert', 'replace')"> <record ID="{current-merge-key()}"> <xsl:copy-of select="current-merge-group('updates')/*"/> </record> </xsl:when> <xsl:when test="current-merge-group('updates')/@action='delete'"/> </xsl:choose> </xsl:merge-action> </xsl:merge>
The xsl:merge
instruction can be used to determine the union,
intersection, or difference of two sequences of numbers (or other atomic values).
This code gives the union:
<xsl:merge> <xsl:merge-source select="1 to 30"> <xsl:merge-key select="."/> </xsl:merge-source> <xsl:merge-source select="20 to 40"> <xsl:merge-key select="."/> </xsl:merge-source> <xsl:merge-action> <xsl:sequence select="current-merge-key()"/> </xsl:merge-action> </xsl:merge>
While this gives the intersection:
<xsl:merge> <xsl:merge-source select="1 to 30"> <xsl:merge-key select="."/> </xsl:merge-source> <xsl:merge-source select="20 to 40"> <xsl:merge-key select="."/> </xsl:merge-source> <xsl:merge-action> <xsl:if test="count(current-merge-group()) eq 2"> <xsl:sequence select="current-merge-key()"/> </xsl:if> </xsl:merge-action> </xsl:merge>