This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: using variable as a value for "use-attribute-sets"


Hi Tony,

> I have a variable declared called "setname"
> I want to use it as the value of  "use-attribute-sets".

Unfortunately you can't. The attributes that refer to other components
in an XSLT stylesheet (e.g. the name of the template that you call,
the mode in which you apply templates, or the attribute sets that you
use) cannot be set dynamically.

There are three ways of approaching this that I can think of.

First, since you know all the possible legal values of the $setname
variable (which is the name of the current node), you can test this
against each of the legal values and decide which attribute set to use
based on this:

  <xsl:choose>
    <xsl:when test="self::para">
      <block xsl:use-attribute-sets="para">
        ...
      </block>
    </xsl:when>
    <xsl:when test="self::heading">
      <block xsl:use-attribute-sets="heading">
        ...
      </block>
    </xsl:when>
    ...
    <xsl:otherwise>
      <block>
        ...
      </block>
    </xsl:otherwise>
  </xsl:choose>

Note that I'm testing the name of the element here using the self::
axis rather than the name() function. This is more reliable when you
use namespaces, so it's good practice.

Also I'm using the more concise method of generating the block
elements with literal result elements rather than xsl:element. The
equivalent with xsl:element would be:

  <xsl:choose>
    <xsl:when test="self::para">
      <xsl:element name="block" use-attribute-sets="para">
        ...
      </xsl:element>
    </xsl:when>
    <xsl:when test="self::heading">
      <xsl:element name="block" use-attribute-sets="heading">
        ...
      </xsl:element>
    </xsl:when>
    ...
    <xsl:otherwise>
      <xsl:element name="block">
        ...
      </xsl:element>
    </xsl:otherwise>
  </xsl:choose>

If the content of the block element is different for the different
types of element, then you should probably split this big xsl:choose
into several separate templates instead.

Second, if the attributes in the attribute sets all have static values
(i.e. they're not computed using xsl:value-of or xsl:choose or
something) then you can retrieve the relevant xsl:attribute-set
element using the document() function and then iterate over the
xsl:attribute elements it holds to create the attributes, as follows:

  <xsl:variable name="setname" select="name()" />
  <xsl:variable name="set"
    select="document('')/*/xsl:attribute-set[@name = $setname]" />
  <block>
    <xsl:for-each select="$set/xsl:attribute">
      <xsl:attribute name="{@name}">
        <xsl:value-of select="." />
      </xsl:attribute>
    </xsl:for-each>
    ...
  </block>

If the attribute sets themselves use attribute sets, then you need to
do this with a recursive template rather than an embedded
xsl:for-each, but hopefully you get the idea.

Third, you can turn the transformation into a two-step process - the
first step generates the stylesheet that you need to perform the
actual transformation on the source document. For example, to generate
the XSLT that will generate the block element, you could use:

  <xsl:variable name="setname" select="name()" />
  <block oxsl:use-attribute-sets="{$setname}">
    ...
  </block>

which, given that the current node at that point had a name of 'para',
would generate the XSLT:

  <block xsl:use-attribute-sets="para">
    ...
  </block>

which you could use to transform that element.

I hope that helps,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]