Jules Colle
Jules Colle

Reputation: 11939

XSLT: can I declare a variable globally and later assign a value to it

What can I do to make this code work?

<xsl:choose>
  <xsl:when test='type = 6'>
    <xsl:variable name='title' select='root/info/title' />
  </xsl:when>
  <xsl:when test='type = 7'>
    <xsl:variable name='title' select='root/name' />
  </xsl:when>
  <xsl:otherwise>
    <xsl:variable name='title'>unknown</xsl:variable>
  </xsl:otherwise>
</xsl:choose>

<div class='title'>
  <xsl:value-of select='$title'/>
</div>

This doesn't work because when i do <xsl:value-of select='$title'/>, $title is out of scope. I tried to add the line <xsl:variable name='title'/> outside of the scope, but that won't work either, because then when i call <xsl:variable name='title' select='root/info/title' /> for example, i already have set this variable before. How should I solve this?

Upvotes: 24

Views: 71094

Answers (6)

cmf41013
cmf41013

Reputation: 107

Yes, you can do that in xlst 2.0, but it's forbidden in xlst 1.0 version.

the code following can run well in my pc with xslt processor saxson-he 9.8.0.12 .

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    exclude-result-prefixes="xs map"
    version="2.0">

    <xsl:template match="/">
        <xsl:variable name="i1" select="123" as="xs:integer"/>
        <xsl:variable name="s1" select="'abcd'" as="xs:string"/>
        <xsl:variable name="d1" select="234.5" as="xs:float"/>

        <!-- we test that variable v1 can be assignment multi times and it is ok. -->
        <xsl:variable name="v1" select="$i1"/>
        v1 is: <xsl:value-of select="$v1"/>
        <xsl:variable name="v1" select="$s1"/>
        v1 is: <xsl:value-of select="$v1"/>
        <xsl:variable name="v1" select="$d1"/>
        v1 is: <xsl:value-of select="$v1"/>

        <xsl:variable name="map1" select="map{'haha':119, 'good':110}"/>
        <xsl:variable name="map2" select="map:put($map1, 'go', 122)"/>
        <xsl:variable name="map1" select="map:put($map2, 'hello', 999)"/>
        map1(haha) is <xsl:sequence select="$map1?haha"/>
        map1(go) is <xsl:sequence select="$map1?go"/>
        map1(hello) is <xsl:sequence select="$map1?hello"/>
    </xsl:template>

</xsl:stylesheet>

reslut of output is that:

v1 is: 123 v1 is: abcd v1 is: 234.5 map1(haha) is 119 map1(go) is 122 map1(hello) is 999

In xslt 1.0, it need recursion function, then pass the value as param.

Upvotes: -1

I'm doing it to save local value to xml xsl:desult_document to folder /temp_variables_loop/loop-data-id_(position()).xml.

And in next loop I read files from /temp_variables_loop.alias/loop-data-id_(position()-1).xml.

You need to cheat xsl engine by make alias of /temp_variables_loop to temp_variables_loop.alias because you cannot read and write to the same file in one xsl.

Upvotes: -1

Dirk Vollmar
Dirk Vollmar

Reputation: 176219

You can't re-assign variables in XSLT (1.0). The name is probably not luckily chosen; an xsl:variable is more a symbol than a variable.

In your sample you can use the following:

<xsl:variable name='title'>
  <xsl:choose>
    <xsl:when test='type = 6'>
      <xsl:value-of select='root/info/title' />
    </xsl:when>
    <xsl:when test='type = 7'>
      <xsl:value-of select='root/name' />
    </xsl:when>
    <xsl:otherwise>
      <xsl:text>unknown</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

Upvotes: 4

user357812
user357812

Reputation:

Besides @carolclarinet's standar answer and more compact @Dimitre's answer, when the result depend on some node and you are worry about reuse and extensibility, you can apply templates and use pattern matching, i.e:

<xsl:variable name="title"> 
    <xsl:apply-templates select="type" mode="title"/> 
</xsl:variable>

<xsl:template match="type[.=6]" mode="title"> 
    <xsl:value-of select='../root/info/title"/> 
</xsl:template> 
<xsl:template match="type[.=7]" mode="title"> 
    <xsl:value-of select='../root/name"/> 
</xsl:template> 
<xsl:template match="type" mode="title"> 
    <xsl:text>unknown</xsl:text> 
</xsl:template>

Upvotes: 2

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243529

<xsl:choose> 
  <xsl:when test='type = 6'> 
    <xsl:variable name='title' select='root/info/title' /> 
  </xsl:when> 
  <xsl:when test='type = 7'> 
    <xsl:variable name='title' select='root/name' /> 
  </xsl:when> 
  <xsl:otherwise> 
    <xsl:variable name='title'>unknown</xsl:variable> 
  </xsl:otherwise> 
</xsl:choose> 

<div class='title'> 
  <xsl:value-of select='$title'/> 
</div> 

This doesn't work

This is a FAQ:

You are defining several variables, each named $title and each useless, because it goes out of scope immediately.

The proper way in XSLT 1.0 to define a variable based on conditions is:

<xsl:variable name="vTitle">
    <xsl:choose>
      <xsl:when test='type = 6'>
        <xsl:value-of select='root/info/title' />
      </xsl:when>
      <xsl:when test='type = 7'>
        <xsl:value-of  select='root/name' />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="'unknown'"/>
      </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

Another way of defining the same variable: In this particular case you want the variable to have a string value. This can be expressed in a more compact form:

<xsl:variable name="vTitle2" select=
"concat(root/info/title[current()/type=6],
        root/name[current()/type=7],
        substring('unknown', 1 div (type > 7 or not(type > 5)))
       )
"/>

Finally, in XSLT 2.0 one can define such a variable even more conveniently:

<xsl:variable name="vTitle3" as="xs:string" select=
 "if(type eq 6)
    then root/info/title
    else if(type eq 7)
            then root/name
            else 'unknown'
 "/>

Upvotes: 15

carols10cents
carols10cents

Reputation: 7014

You can move the choose inside the setting of the variable, like this:

<xsl:variable name="title">
  <xsl:choose>
    <xsl:when test='type=6'>
      <xsl:value-of select="root/info/title" />
    </xsl:when>
    ...
  </xsl:choose>
</xsl:variable>

<div class='title'>
  <xsl:value-of select="$title" />
</div>

Upvotes: 36

Related Questions