I have an XML schema that contains the following type :
<xs:simpleType name="valuelist">
<xs:list itemType="xs:double"/>
</xs:simpleType>
A sample XML fragment would be:
<values>1 2 3.2 5.6</values>
In an XSLT transform, how do I get the number of elements in the list?
How do I iterate over the elements?
I. XPath 2.0 (XSLT 2.0) solution:
count(tokenize(., ' '))
II. XPath 1.0 (XSLT 1.0) solution:
string-length()
-
string-length(translate(normalize-space(), ' ', ''))
+ 1
As for iteration over the items of this list:
- In XPath 2.0 / XSLT 2.0 just use the above XPath 2.0 expression as the value of a
select
attribute:
--
for $i in tokenize(., ' '),
$n in number($i)
return
yourXPathExpression
--
2.
In XSLT 1.0 you need to have some more code for splitting/tokenization. There are several good answers to this question (part of them mine) -- just search for something like "xslt split a string"
If list is strictly spaced, you can count spaces based on string length.
<values>1 2 3.2 5.6</values>
XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<xsl:value-of select="string-length(values)
- string-length(translate(values, ' ', '')) + 1"/>
</xsl:template>
</xsl:stylesheet>
To iterate over elements you have to split this string. There a lot of examples at SO.
In a schema-aware transformation, use count(data(value))
.
With a little imagination you can write your own split function :
<xsl:stylesheet version = '1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method='text'/>
<xsl:template name="split-list">
<xsl:param name="list" />
<xsl:param name="separator"/>
<xsl:variable name="newlist" select="concat(normalize-space($list), $separator)" />
<xsl:variable name="first" select="substring-before($newlist, $separator)" />
<xsl:variable name="remaining" select="substring-after($newlist, $separator)" />
<xsl:message terminate="no">
<xsl:value-of select="$first" />
</xsl:message>
<xsl:if test="$remaining">
<xsl:call-template name="split-list">
<xsl:with-param name="list" select="$remaining" />
<xsl:with-param name="separator" select="$separator"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="myList">
1 2 3.2 5.6
</xsl:variable>
<xsl:call-template name="split-list">
<xsl:with-param name="list" select="$myList" />
<xsl:with-param name="separator">
<xsl:text> </xsl:text>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
Output :
[xslt] Loading stylesheet D:\Tools\StackOverFlow\test.xslt
[xslt] 1
[xslt] 2
[xslt] 3.2
[xslt] 5.6