0

Consider the schema:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="TheList">
        <xs:simpleType>
            <xs:list itemType="xs:string" />
        </xs:simpleType>
    </xs:element>
</xs:schema>

And the xml:

<TheList>
    This list has 5 values.
</TheList>

How can I iterate over each of the words in the list? To create something like:

<item>This</item>
<item>list</item>
<item>has</item>
<item>5</item>
<item>values.</item>

Based on the answers I've found here and here, I should do something like:

<xsl:stylesheet version="3.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="TheList">
        <xsl:for-each select="tokenize(., ' ')">
            <item><xsl:value-of select="." /></item>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

However, at least in Altova's XML spy, I am getting this error:

Wrong occurrence to match required sequence type: The supplied sequence ('5' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one')

Using the built in debugger, I have been able to determine that the error is thrown when calling tokenize on an element that has been declared as an xs:list. Which makes sense, since the element should already be split according to the rules regarding xs:list. To me, this suggests:

<xsl:stylesheet version="3.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="TheList">
        <xsl:for-each select=".">
            <item><xsl:value-of select="." /></item>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

However, this treats the list as a single item and does not create a new item element for each word.

The for-each command seems to treat the xs:list as a single element while the tokenize function seems to treat the same xs:list as multiple elements. What am I missing?

Community
  • 1
  • 1
eisenpony
  • 565
  • 4
  • 10

1 Answers1

3

If you're using a schema-aware transformation, then you don't need to tokenize the value yourself - the process of atomization does it for you automatically.

<xsl:template match="TheList">
    <xsl:for-each select="data(.)">
        <item><xsl:value-of select="." /></item>
    </xsl:for-each>
</xsl:template>

If you want the code to work in both schema-aware and non-schema-aware environments you can write

<xsl:template match="TheList">
     <xsl:for-each select="tokenize(string(.), ' ')">
        <item><xsl:value-of select="." /></item>
     </xsl:for-each>
</xsl:template>
Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Thanks Michael. Now I see your answer in http://stackoverflow.com/questions/7725581/how-do-i-find-the-number-of-elements-in-a-xslist-using-xslt which should have clued me in! – eisenpony May 13 '15 at 15:07