Search

This is most likely something obvious to those of you that are seasoned XSLT meisters; however, it’s had me stuck for a couple days. There seems to be a difference in the way the select attribute of an XSLT param works and the way the select attribute of an XSLT value-of works. I need help understanding the difference and how to achieve the conditional output needed. So first, here’s a conceptual example.

Example XML

<data>
    <my-node-set>
        <item>Item 1</item>
        <item>Item 2</item>
        <item>Item 3</item>
    </my-node-set>
</data>

Example XSLT Problem

<xsl:template name="node-count">
    <xsl:param name="node-set"/>

    <xsl:variable name="node-set-b">
        <xsl:value-of select="$node-set"/>
    </xsl:variable>

    <!-- Result = 3 -->
    <xsl:value-of select="count($node-set)"/>

    <!-- Result = XSLT error "The 'select' expression did not evaluate to a node set." -->
    <xsl:value-of select="count($node-set-b)"/>

</xsl:template>

<xsl:apply-templates match="/data">
    <xsl:call-template name="node-count">
        <xsl:param name="node-set" select="my-node-set/item"/>
    </xsl:call-template>
</xsl:apply-templates>

Problem Restated

Why does the <value-of select="..."/> render a string instead of the node that is passed to the template?

Well it’s in the name of the element: xsl:value-of always return the value (= text string) of the passed reference. So using this:

<xsl:variable name="node-set-b">
    <xsl:value-of select="$node-set"/>
</xsl:variable>

will store Item 1 Item 2 Item 3 in the variable $node-set-b which can’t be evaluated using count().

What exactly are you trying to achieve? Does xsl:copy-of help in your case?

@Nils thank you for your help.

I have a front-end form that I use for both the adding of new records and then editing of existing records within Symphony. In attempts at refactoring, I have a template that I call and I need to be able to either use the node set sent to the template or not. When I pass the it works but when I attempt to add any conditional aspects within the <xsl:param/> I can’t seem to pass a node set. For example:

<xsl:with-param name="selected-path" select="$data-path/groups-in-the-loop/item"/>

This works, passing the node set without respect of whether or not the form needs the dataset (i.e., if it was begin used to edit an existing record). When I add the conditional language I get xslt errors.

<xsl:with-param name="selected-path">
    <xsl:choose>
        <xsl:when test="$sub1 = 'edit'">
            <xsl:value-of select="$data-path/groups-in-the-loop/item"/>
        </xsl:when>
    </xsl:choose>
</xsl:with-param>

What is the error?

@ashooner - I get this vague xslt error:

XSLTProcessor::transformToXml(): Invalid type
XSLTProcessor::transformToXml(): xmlXPathCompiledEval: 1 objects left on the stack.

If I change the <xsl:value-of … to <xsl:apply-templates … I get this:

XSLTProcessor::transformToXml(): The 'select' expression did not evaluate to a node set.

Thanks for your help.

You should try xsl:copy-of instead of xsl:value-of and you need to move your choose statement into a variable as I’m quite sure that xsl:with-param need to be self-closing.

Keep in mind that if you do copy-of instead of value-of, you’ll be storing a Result Tree Fragment, not a node set, which has limited use. However, you should be able to set the param value as you have it (see here).

I can’t replicate your error yet, will get back to you.

OK a couple things:

Not sure if this is in your active problem code but,

<xsl:apply-templates match="/data">
    <xsl:call-template name="node-count">
        <xsl:param name="node-set" select="my-node-set/item"/>
    </xsl:call-template>
</xsl:apply-templates>

This is an error, the apply-templates needs a select attribute rather than match, or should this be a template element rather than apply-templates?

I replicated your type error by attempting to apply XPath to the param in the destination template (the template being passed the parameter in question). What are you doing with the param in the destination template?

If you need to get a count or run XPath on the content of that parameter, you’ll either need to do that in the first pass (so it isn’t converted to a RTF) and pass the result as the parameter value, or use the exsl:node-set function.

@ashooner You are right. Forgive me for the hurried example. I wrote it out in pastie and did not have the luxury of <oXygen/> to correct my mistake.

In the mean time, we came up with a solution, that unfortunately does not enlighten me as to why it works and the other ways listed above do not, but that it works is a relief. Here is the actual (not exemplary) code:

<xsl:choose>
    <xsl:when test="$sub1 = 'edit'">
        <xsl:call-template name="field-groups-in-the-loop">
            <xsl:with-param name="event-path" select="$event-path"/>
            <xsl:with-param name="selected-path" select="$data-path/groups-in-the-loop/item"/>
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:call-template name="field-groups-in-the-loop">
            <xsl:with-param name="event-path" select="$event-path"/>
        </xsl:call-template>
    </xsl:otherwise>
</xsl:choose>

Conclusion

  1. <xsl:with-param ... select="..."/> treats xpath values different than <xsl:value-of select="..."/> does.
  2. Consequently, conditional statements within <xsl:with-param> tags in which the value is xpath oriented rather than text based is not recommended. One should call the relevant template in two separate instances so that xpath values can be given only in the <xsl:with-param select="..."/> manner.

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details