Is there a way to walk-through a key and output all the values it contains?
<xsl:key name="kElement" match="Element/Element[@idref]" use="@idref" />
I though of it this way:
<xsl:for-each select="key('kElement', '.')">
<li><xsl:value-of select="." /></li>
</xsl:for-each>
However, this does not work. I simply want to list all the values in a key for testing purposes.
The question is simply: how can this be done?
You can't. That's not what keys are for.
You can loop through every element in a key using a single call to
key()
if and only if the key of each element is the same.If you need to loop over everything the key is defined over, you can use the expression in the
match="..."
attribute of your<key>
element.So if you had a file like this:
And a key defined like this:
You can loop through what the key uses by using the contents of its
match
attribute:Alternatively, if each element had something in common:
Then you could define your key like this:
And iterate over all elements like this:
Because each element shares the value "survivor" for the
class
attribute.In your case, your key is
So you can loop through everything it has like this:
Rather than think of the XSL keys in programming language terms, think of them as record sets of SQL. That will give a better understanding. For a given key index created as
it can be "iterated"/"walk-through" as below
To understand this magic number
[1]
, let s go through the below example :Consider this XML snippet
transformed using this XSL.
The above XSL transformation lists the unique id of the
Person
nodes and thecost
nodes in the form ofidpxxxxxxx
as the result below shows.Let us create a key on the
cost
records using a combination ofname
anditemID
values.Manually looking at the XML, the number of unique keys for the above would be three : Johny+1, Johny+2 and Johny+3.
Now lets test out this key by using the snippet below.
And here is the result:
Our interest is in trying to understand the importance of
[1]
,[2]
,[3]
,[4]
. In our case, the keygenerator isconcat(../name, '+', @itemID)
.For a given key,
[1]
refers to the first occurence of a node that satisfies the keygenerator. Similarly[2]
refers to the second occurence of a node that satisfies the keygenerator. Thus[2]
,[3]
,[4]
, etc. are all nodes that satisfy the same key, and thus can be considered duplicates for the given key. The number of duplicates depends on the input XML. Thus:Thus we see that ALL 8
cost
nodes of the XML can be accessed through the key.Here is a image that combines the transformation results to help better understand.
The red squares indicate the matching nodes for Johny+1. The green squares indicate the matching nodes for Johny+3. Match the
idpxxxxxxx
values in<costkeygroup>
to the values in<costrecords>
. The<costrecords>
help map theidpxxxxxxx
values to the source XML.The takeaway is that,
To "walk through" only unique nodes of the key in the above example, use
[1]
signifies that the first record for a given key value is denoted as the unique record.[1]
is almost always used because there will exist at least one node that satisfies a given key value. If we are sure that there will be a minimum of 2 records to satisfy each key value in the key, we can go ahead and use[2]
to identify the second record in the record set as the unique record.P.S The words nodes / records / elements are used interchangeably.
There is no way to walk-through the keys, although we can output all the values it contains. In XSLT2 it is quite easier than in XSLT1 (e.g., using
fn:generate-id
according to the previous answer).Using
fn:distinct-values
Using
xsl:for-each-group
You CAN create a key to use for looping - if you simply specify a constant in the use attribute of the key element:
Then you can loop over all elements in the following way:
Or count them:
Note that the constant can be any string or even a number - but 'all' reads well.
However, you cannot use this key to lookup information about the individual entries (because they all have the same key).
In other words there are two types of possible keys:
I do not know how efficient this method is to execute, it does however make the maintenance of the XSL more efficient by avoiding repetition of the same (potentially very complex) XPath expression throughout the XSL code.