1

I have this XSLT:

<xsl:template match="/">

    <xsl:variable name="errorCount" select="count($orders/*[1]/cm:Error)" />

    <xsl:apply-templates select="@*|node()">
        <xsl:with-param name="errorCount" select="$errorCount" tunnel="yes" />
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="status">
    <xsl:param name="errorCount" tunnel="yes" />
    <xsl:copy>
        <xsl:choose>
            <xsl:when test="$errorCount > 0">
                <xsl:text>ERROR</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>OK</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

The tunneling and all seems to work, but the transformation fails with the following error:

Required item type of first operand of '>' is numeric; supplied value has item type xs:string

I first had the variable declaration in the template where it is it used, and then it worked fine. Moved it because I need to use the same count in other templates too.

How/Where do I declare that this variable/parameter is in fact a number?

Svish
  • 152,914
  • 173
  • 462
  • 620
  • The value of the tunnel attribute must be "yes" or "no", not "true" or "false". Are you showing us the code you are executing? – Michael Kay Feb 19 '13 at 16:17
  • ah, yes, that's a bug I found right after I had asked this. Also added the `number` function to make it work in the test. But will check out the `as` attribute tomorrow :) – Svish Feb 19 '13 at 16:29

3 Answers3

7

Since you are using XSLT 2.0, then you should also add an as attribute to your xsl:param in the template. For example (you may have to use a different as value depending on what you need the resulting number to be, such as if you'll have values that have decimals; you would also need to correct the tunnel value, per Michael Kay's point):

<xsl:param name="errorCount" tunnel="yes" as="xs:integer" />

The transform would fail if it couldn't be converted to the as type (in this case, an integer). Eero's solution may look cleaner because you'll still have to check to see if the value is greater than zero. But, because you are using XSLT 2.0, the best practice is to type your parameters/variables.

TddOrBust
  • 450
  • 2
  • 9
  • So do I need `as` on the `param` only, or also on the `with-param` and `variable` elements? – Svish Feb 19 '13 at 16:01
  • 1
    It does no harm to put it everywhere. The most important place, however, is xsl:param, because that's where the system can't work out the type for itself. – Michael Kay Feb 19 '13 at 16:16
  • Seems like it works when I just fixed the `tunnel="true"`->`tunnel="yes"` issue, but accepting this anyways since it answers my actual question :) – Svish Feb 20 '13 at 09:48
2

You can use number() to convert a string to a number:

<xsl:when test="number($errorCount) > 0">
  <xsl:text>ERROR</xsl:text>
</xsl:when>
Community
  • 1
  • 1
Eero Helenius
  • 2,584
  • 21
  • 22
  • This works great, and is how I "fixed" it for now, but want to do it right since it shouldn't be necessary to convert a number to a number for it to be a number :p – Svish Feb 19 '13 at 16:02
  • Can't disagree with you there. :) With regards to "doing it right", I'd suggest taking a look at Dr. Kay's answer. – Eero Helenius Feb 19 '13 at 17:05
2

My suspicion is that because you wrote tunnel="true" rather than tunnel="yes", the fact that you specified tunnel at all is being (incorrectly) ignored, and the parameter is being given its default value, which is a zero-length string.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Seems like this actually fixed the issue! Still accepted the `as` answer, since that actually answered my question *How/Where do I declare variable/parameter is a number* though. – Svish Feb 20 '13 at 09:47