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: jumping out of a loop revisited


Hi Tanzila,

It looks as though you have some general output that should be created
for most of the children of the Grasslands element, and then some
specialised output for the LinksForTheGenus and References elements.

This is a classic example of where using *push* (letting the source
XML drive the process, just applying templates to everything and
letting the XSLT processor sort out what to do) is a good strategy.

So, first made a template for the normal processing of one of the
children of Grasslands:

<!-- this template matches any child element of Grasslands -->
<xsl:template match="Grasslands/*">
   <h3><font color="#00007F">
      <i><xsl:value-of select="name()" /></i>
      </font></h3>
   <p><font color="#008000"><xsl:value-of select="." /></font></p>
</xsl:template>

Then make templates for the specialised elements.  These need to be
given a priority that's more than 0.5, so that they override the
general template given above:

<!-- this template matches the LinksForTheGenus element -->
<xsl:template match="Grasslands/LinksForTheGenus" priority="1">
   <h3>
      <a name="Label0045"></a>
      <font color="#00007F"><i>Links for the genus:</i></font>
   </h3>
   <ul>
      <!-- iterates over the Link elements within the LinksForTheGenus
           element -->
      <xsl:for-each select="Link">
         <li><font color="#008000">
            <xsl:value-of select="Address" />;&#xA;<xsl:text />
            <xsl:value-of select="Name" />
            </font></li>
      </xsl:for-each>
   </ul>
</xsl:template>

<!-- this template matches the References element -->
<xsl:template match="Grasslands/References" priority="1">
   <!-- iterates over the Ref elements within the References element
        -->
   <xsl:for-each select="Ref">
      <font color="#0080000">
         <xsl:value-of select="Name" />
         <xsl:text>&#xA; </xsl:text>
         <xsl:value-of select="Year" />;&#xA;<xsl:text />
      </font>
   </xsl:for-each>
</xsl:template>

With these templates in place, all you have to do is tell the
processor to apply templates to the elements you're interested in.
The processor will automatically find the right template for each
element and use it.

So within a template that matches the Grasslands element, tell the
processor to apply templates to the 4th child element onwards, as long
as it actually has some content:

<xsl:template match="Grasslands">
   <xsl:apply-templates select="*[position() > 3 and text()]" />
</xsl:template>

[Aside: a couple of things here - you might find that it's more
extensible not to use the position of an element to determine whether
it should get processed, but rather filter out the elements that you
don't want to have templates applied to by name.  I don't know what
your source looks like, but usually you should only use the position()
of an element if you have repeated elements.  The second thing is that
the text() test sees whether there are any text nodes within a
particular element.  That means that it may succeed with:

  <description>     </description>

and fail with:

  <description><b>Blah blah</b></description>

Usually, I'd use normalize-space() to see whether an element has any
textual content or not, rather than text().]

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]