Re: [xsl] Design question

Subject: Re: [xsl] Design question
From: Peter Davis <pdavis152@xxxxxxxxx>
Date: Tue, 9 Jul 2002 17:37:50 -0700
On Tuesday 09 July 2002 15:12, Jay Burgess wrote:
> (1) Iterate through all original <param>s. For each <param> that will
> become an attribute, do <xsl:attribute>. For each <param> that will become
> a child element, store it off to the side in a node set of some sort.

It's rather difficult (impossible?) to store the non-attribute params off into 
some temporary variable.  This means that you can't process all the params in 
one step -- you have to process the attribute params first, and then the 
element params, in two separate steps.

One possible way to do this is to use template modes, which let you iterate 
through all of the params twice with different outputs.

<xsl:template match="test">
  <xsl:variable name="type">
    <!-- figure out the name of the <da:Positive> element based on @type -->
    <xsl:choose>
      <xsl:when test="@type = 'positive'">Positive</xsl:when>
      <xsl:otherwise>...</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  
  <xsl:element name="{$type}" namespace="the namespace of the 'da' prefix">
    <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
    <xsl:apply-templates select="param" mode="param-attributes"/>
    <xsl:apply-templates select="param" mode="param-elements"/>
  </xsl:element>
</xsl:template>

Now all that is left is to define two (sets of?) templates that match <param>, 
one for param's that are attributes with mode="param-attributes", and another 
with mode="param-elements".  Exactly how this is done depends on how you know 
whether or not a param is supposed to be an element or attribute.  I assume 
you know beforehand at least one of those.

I'm going to pretend that you only know the list of params that will be 
elements -- hopefully it will be obvious how to change this if you need 
something different.  I'm assuming that if the param's name starts with 
"date" or is equal to "foo", then it is an element; if the name *not* does 
not start with "date" or is not equal to "foo", then it is an attribute.  
This is of course just an example.

You can either have one template for each mode with a giant conditional 
(xsl:choose or xsl:if), or you can have several templates that use predicates 
in the match expression.  I'm going to use the conditional route:

<xsl:template match="param" mode="param-attributes">
  <xsl:if test="not(starts-with(@name, 'date'))
                and @name != 'foo2'">
    <xsl:attribute name="{@name}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:if>
  <!-- otherwise don't output an attribute -->
</xsl:template>

<xsl:template match="param" mode="param-elements">
  <xsl:choose>
    <xsl:when test="starts-with(@name, 'date')">
      <da:Date number="{substring-after(@name, 'date')}"
               value="{.}"/>
    </xsl:when>
    <xsl:when test="@name = 'foo'">
      <da:Foo .../>
    </xsl:when>
    <!-- otherwise don't output an element -->
  </xsl:choose>
</xsl:template>

HTH!

-- 
Peter Davis

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


Current Thread