1

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.

Community
  • 1
  • 1
ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
  • 1
    Consider to show us a minimal but complete snippet of XML input, XSLT code and output you want. I am afraid inside for your for-each with `tokenize` the context item is a string so doing `name()` for any outside context node is not going to work. You can however perhaps simply use `` which would make the variable true if the name of the context node is equal to at least one token. – Martin Honnen Mar 14 '17 at 19:56
  • Can we assume that because you are using tokenize() you are looking for an XSLT 2.0 solution? You really need to say (using the tag xslt_1.0 or xslt_2.0) because otherwise people answering the question can waste a lot of time. – Michael Kay Mar 14 '17 at 22:50

2 Answers2

1

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.

zx485
  • 28,498
  • 28
  • 50
  • 59
1

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".

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • So `=` can mean `contains`? Which versions of XSLT does this work with? – ArtOfWarfare Mar 14 '17 at 22:56
  • If you're using XSLT/XPath you really shouldn't need to ask that question. If you don't know how "=" works in XPath (or whatever other language you write in), then the code you write is going to give you a lot of surprises. Yes, X=Y in XPath means "some item in X is equal to some item in Y". – Michael Kay Mar 14 '17 at 23:00