ArtOfWarfare
ArtOfWarfare

Reputation: 21496

Choose with for-each inside?

I have a parameterignoreAttributes which is a comma separated list of things to look for. I want to set a variable copyAttrib to be equal to whether any of them are exactly matched by name().

If xsl were a procedural language where variables could be reassigned, I'd use something like this:

<xsl:variable name="copyAttrib" select="true()">
<xsl:for-each select="tokenize($ignoreAttributes,',')">
    <xsl:if test="compare(., name()) != 0">
        <xsl:variable name="copyAttrib" select="false()"/>
    </xsl:if>
</xsl:for-each>

Unfortunately, I can't do that, because xsl is functional (so says this other answer). So variables can only be assigned once.

I think the solution would look something like:

<vsl:variable name="copyAttrib">
    <xsl:choose>
        <xsl:when>
            <xsl:for-each select="tokenize($ignoreAttributes, ',')">
                <xsl:if test="compare(., name()) != 0"/>
            </xsl:for-each>
        <xsl:otherwise>
            <xsl:value-of select="false()"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

Obviously not exactly that (otherwise I wouldn't be asking.)

I know that I could bypass the tokenize and for-each loop by just using replaces on ignoreAttributes and changing all the , to | and then using matches, but I'd like to avoid that if possible because then I need to deal with the possibility that ignoreAttributes (which the user provides) might contain some special characters that will change the regex pattern and escape them all.

Upvotes: 1

Views: 1581

Answers (2)

Michael Kay
Michael Kay

Reputation: 163458

I have a parameterignoreAttributes which is a comma separated list of things to look for. I want to set a variable copyAttrib to be equal to whether any of them are exactly matched by name().

That sounds to me like

<xsl:variable name="copyAttrib" as="xs:boolean"
  select="tokenize($parameterignoreAttributes, ',') = name()"/>

You say:

Unfortunately, I can't do that, because xsl is functional

when what you mean is: "Fortunately, I don't need to do that, because XSLT is functional".

Upvotes: 1

zx485
zx485

Reputation: 29042

An XSLT-1.0 way of doing this is by using a recursive, named template:

  <xsl:template name="copyAttrib">
    <xsl:param name="attribs" />
    <xsl:choose>
        <xsl:when test="normalize-space(substring-before($attribs,',')) = normalize-space(name(.))">
          <xsl:value-of select="'true'" />
        </xsl:when>
        <xsl:when test="normalize-space($attribs) = ''">
          <xsl:value-of select="'false'" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="copyAttrib">
            <xsl:with-param name="attribs" select="substring-after($attribs,',')" />
          </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

Apply this template onto the current, the selected, node and wrap it in a <xsl:variable>:

<xsl:variable name="copyAttribResult">
  <xsl:call-template name="copyAttrib">
    <xsl:with-param name="attribs" select="'a,b,c,...commaSeparatedValues...'" />
  </xsl:call-template>
</xsl:variable>

to get either true or false as a result.

Upvotes: 1

Related Questions