XSLT optional attributes

Eric Anderson

Usenet Archive
Joined
Dec 8, 2000
Messages
44
Reaction score
0
I'm not sure if this is the correct place to post this question so please feel free to redirect me if needed.

I am writing a XSL transform document to perform a transform on an XML document. I want some of my XML tags to have optional attributes. If the person does not specify the value of an attribute I will assume a default value. What is the best way to do this in XSL. Let me give an example to make my problem clear:

foo.xml

<root>
<tag attr="value"/>
<tag attr="another_value"/>
</root>

bar.xsl
<xsl:template match="/root/tag">
Attribute 'attr' is <xsl:value-of select="@attr"/>
</xsl:template>

output
Attribute 'attr' is value
Attribute 'attr' is another_value

Now lets make one change to the above transforms. We want the attribute 'attr' to default to the value of "default" if not specified. Now one way to do this would be:

bar.xsl
<xsl:template match="/root/tag">
<xsl:choose>
<xsl:when test="@attr = ''">
Attribute 'attr' is default
</xsl:when>
<xsl:eek:therwise>
Attribute 'attr' is <xsl:value-of select="@attr"/>
</xsl:eek:therwise>
<xsl:choose>
</xsl:template>

The solution above is not really scalable. What if you want to have lots of attributes that have defaults? And what if you are doing more than printing a sentence out? Do you really want to repeat hundreds of lines with just a few small changes between the different blocks of code? A better method is if we could at the top of our template simply check if the value is set. If it is not set then we would want to be able to set it. My first thought was to use <xsl:variable> tag like below:

<xsl:template match="/root/tag">
<xsl:choose>
<xsl:when test="@attr = ''">
<xsl:variable name="attr" select="'default'"/>
<xsl:when>
<xsl:eek:therwise>
<xsl:variable name="attr" select="@attr"/>
<xsl:eek:therwise>
</xsl:choose>
Attribute 'attr' is <xsl:value-of select="$attr"/>
</xsl:template>

The problem is that the variable 'attr' seems to only be defined in the context of the conditional (at least it seems to be that way in Mozilla's XSLT processing). Once the conditional has ended (xsl:choose) then it is no longer defined. I tried to define an empty variable 'attr' prior to the conditional to indicate it should be defined in the scope of the template tag not the conditional tags, but that violate the rule of not being allowed to change a the value of a variable (by the way, who was the idiot that thought it was a good idea to have a tag which defines constants and call it a variable! :) ).

So does anyone have any good ideas on how I would get around this? What is the right way to do this in XSLT?

Thanks for your suggestions,

Eric
 

Peter Gerstbach

Usenet Archive
Joined
Aug 11, 2004
Messages
13
Reaction score
0
Hi Eric,

you are right, the scope of xsl:variable ist only the current element. But you can place the xsl:when inside the xsl:variable

<xsl:variable name="attr">
<xsl:when test="@attr = ''">
<xsl:value-of select="'default'"/>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="@attr"/>
<xsl:eek:therwise>
</xsl:variable>

then it should be possible to reference to $attr afterwards in the template. I did not tried it but I hope it works!

Peter

Eric Anderson wrote:
....
 

Richard Tobin

Usenet Archive
Joined
Jan 6, 2000
Messages
4,251
Reaction score
0
Eric Anderson said:
<xsl:template match="/root/tag">
<xsl:choose>
<xsl:when test="@attr = ''">
Attribute 'attr' is default
</xsl:when>
<xsl:eek:therwise>
Attribute 'attr' is <xsl:value-of select="@attr"/>
</xsl:eek:therwise>
<xsl:choose>
</xsl:template>

You might consider a different approach:

<xsl:template match="/root/tag">
Attribute 'attr' is <xsl:apply-templates mode="attr-default" select="."/> </xsl:template>

<xsl:template mode="attr-default" match="*[@attr]">
<xsl:value-of select="@attr"/>
</xsl:template>

<xsl:template mode="attr-default" match="*">
<xsl:text>default</xsl:text>
</xsl:template>

Or you could use a named template containing <xsl:choose>.

-- Richard
 

Eric Anderson

Usenet Archive
Joined
Dec 8, 2000
Messages
44
Reaction score
0
Richard said:
You might consider a different approach:

<xsl:template match="/root/tag">
Attribute 'attr' is <xsl:apply-templates mode="attr-default" select="."/> </xsl:template>

<xsl:template mode="attr-default" match="*[@attr]">
<xsl:value-of select="@attr"/>
</xsl:template>

<xsl:template mode="attr-default" match="*">
<xsl:text>default</xsl:text>
</xsl:template>

Or you could use a named template containing <xsl:choose>.

I thought about these methods, but both have the same problem as my first suggestion. It doesn't scale well. What if I have a tag that has 10 attributes and the tag has lots of complex code.

Thanks for the suggestion anyway,

Eric
 

Eric Anderson

Usenet Archive
Joined
Dec 8, 2000
Messages
44
Reaction score
0
Peter said:
you are right, the scope of xsl:variable ist only the current element. But you can place the xsl:when inside the xsl:variable

<xsl:variable name="attr">
<xsl:when test="@attr = ''">
<xsl:value-of select="'default'"/>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="@attr"/>
<xsl:eek:therwise>
</xsl:variable>

then it should be possible to reference to $attr afterwards in the template. I did not tried it but I hope it works!

I haven't tried it yet, but I am sure this method works and it is exactly what I was looking for. I haven't been a XSLT hacker very long so I am still getting used to it's funky way of doing things. I guess it is not much different than C-based languages having the following construct:

_attr = attr ? bar : "default";

Thanks for your help,

Eric
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
548,208
Messages
3,104,802
Members
249,594
Latest member
henrywalsh

Latest Threads

Top