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]

Re: The use of a variable in use-attribute-sets attribute


Hi Joshua,

Just a couple of insights that might help you get to a more concise
solution.  First, all those xsl:element elements can be created with
literal result elements instead:

<xsl:template match="td">
   <fo:table-cell>
      <xsl:apply-templates select="@class"/>
      <fo:block>
         <xsl:apply-templates />
      </fo:block>
   </fo:table-cell>
</xsl:template>

Second, in the @class-matching template, since you're creating the
same attributes each time, just with different values, then you could
do the xsl:choose within each of the xsl:attribute elements instead of
the other way round.

<xsl:template match="@class">
   <xsl:attribute name="font-size">
      <xsl:choose>
         <xsl:when test=". = 'classname1'">12pt</xsl:when>
         <xsl:when test=". = 'classname2'">14pt</xsl:when>
         <xsl:when test=". = 'classname3'">16pt</xsl:when>
      </xsl:choose>
   </xsl:attribute>
   <xsl:attribute name="font-weight">
      <xsl:choose>
         <xsl:when test="@class = 'classname3'">normal</xsl:when>
         <xsl:otherwise>bold</xsl:otherwise>
      </xsl:choose>
   </xsl:attribute>
</xsl:template>

Now, one thing about attribute sets is that they *can* include
attributes whose values are calculated on the fly, based on the
current node.  So rather than having this separate template to create
the attributes, you could have an attribute set that does the same
thing, based on the @class attribute of the current node:

<xsl:attribute-set name="td-font">
   <xsl:attribute name="font-size">
      <xsl:choose>
         <xsl:when test="@class = 'classname1'">12pt</xsl:when>
         <xsl:when test="@class = 'classname2'">14pt</xsl:when>
         <xsl:when test="@class = 'classname3'">16pt</xsl:when>
      </xsl:choose>
   </xsl:attribute>
   <xsl:attribute name="font-weight">
      <xsl:choose>
         <xsl:when test="@class = 'classname3'">normal</xsl:when>
         <xsl:otherwise>bold</xsl:otherwise>
      </xsl:choose>
   </xsl:attribute>
</xsl:attribute-set>

Then you could just use the attribute set in the normal way:

<xsl:template match="td">
   <fo:table-cell xsl:use-attribute-sets="td-font">
      <fo:block>
         <xsl:apply-templates />
      </fo:block>
   </fo:table-cell>
</xsl:template>

So, that's fine if you want to create the same attributes all the
time - you can change their values based on the class name.

Another thing you could do is create separate attribute sets, but
rather than use them with xsl:use-attribute-sets, access them
programmatically, using them to define the attributes that you want to
add.  So you could define the separate attribute sets:

<xsl:attribute-set name="classname1">
   <xsl:attribute name="font-size">12pt</xsl:attribute>
   <xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:attribute-set>

<xsl:attribute-set name="classname2">
   <xsl:attribute name="font-size">14pt</xsl:attribute>
   <xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:attribute-set>

<xsl:attribute-set name="classname3">
   <xsl:attribute name="font-size">16pt</xsl:attribute>
   <xsl:attribute name="font-weight">normal</xsl:attribute>
</xsl:attribute-set>

You can then access these using the document() function to access the
current stylesheet as a node tree, and then apply templates to the
relevant attribute set according to the class name:

<xsl:template match="td">
   <xsl:variable name="class" select="@class" />
   <fo:table-cell>
      <xsl:apply-templates
         select="document('')/*/xsl:attribute-set[@name = $class]" />
      <fo:block>
         <xsl:apply-templates />
      </fo:block>
   </fo:table-cell>
</xsl:template>

Then have a template that matches an attribute set and goes through
each of the xsl:attribute elements within it to add the relevant
attributes:

<xsl:template match="xsl:attribute-set">
   <xsl:for-each select="xsl:attribute">
      <xsl:attribute name="{@name}">
         <xsl:value-of select="." />
      </xsl:attribute>
   </xsl:for-each>
</xsl:template>

Once you make *that* realisation, it becomes clear that you *could*
define the attributes to be generated for particular classes within
its own XML structure, elsewhere.  You might find it more convenient
to do something like:

<classes>
   <class name="classname1" font-size="12pt" font-weight="bold" />
   <class name="classname2" font-size="14pt" font-weight="bold" />
   <class name="classname3" font-size="16pt" font-weight="normal" />
</classes>

Assuming that $classes holds a node set containing those class
elements (you might access them from a separate document using the
document() function, for example), then with this syntax you could
just *copy* the relevant attributes onto the fo:table-cell:

<xsl:template match="td">
   <xsl:variable name="class" select="@class" />
   <fo:table-cell>
      <xsl:copy-of select="$classes[@name = $class]" />
      <fo:block>
         <xsl:apply-templates />
      </fo:block>
   </fo:table-cell>
</xsl:template>

This type of approach is good if you have fixed *values* for the
various attributes, but might change *which* attributes should be
added for particular classes.

Anyway, sorry for the (characteristically) long mail, but I just
wanted to show some alternative ways of approaching the problem.

Cheers,

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]