This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
RE: conditional template matching & failure
- From: "Michael Kay" <michael dot h dot kay at ntlworld dot com>
- To: <xsl-list at lists dot mulberrytech dot com>
- Date: Tue, 16 Jul 2002 08:43:40 +0100
- Subject: RE: [xsl] conditional template matching & failure
- Reply-to: xsl-list at lists dot mulberrytech dot com
> Generally, I have an XML file with student schedule
> information in it and I want to print each class out when
> given a specific student & term. A student may not exist in
> the XML file, however, for whatever reason.
>
>
> > if student & term found
> > print schedule
> > else
> > give a "not found" msg
>
> ---------
> Problems:
> ---------
>
> 1. Without using xsl:if or :choose, I can't stop a failed
> template match from dumping the entire data
If your template rule isn't selected, the built-in template rule is
selected, and this does an implicit <xsl:apply-templates/>. If you want
it to do nothing, override it like this:
<xsl:template match="schedule"/>
And by the way, you don't need "//" at the start of a match pattern.
>
> Example:
> <xsl:template match="//schedule[@username=$thisUser]">
> ...
> </xsl:template>
>
> Results: prints out entire XML if $thisUser is not found
>
>
> 2. Using xsl:if and :choose doesn't traverse me down the tree
> to the elements I want to print, so I'm writing long (and
> expensive) XPaths on the subsequent condition
>
> Example:
> <xsl:for-each
> select="//schedule[@username=$thisUser]/semester[season=$thisS
> eason and year=$thisYear]/course">
> ...
> </xsl:for-each>
>
> Results: long, slow, inefficient XPath - should just be
> able to say "for-each select='course'"
You can write a relative path expression if you get the context right.
The context node is a <schedule> element, so the relative path you need
is
select="semester[season=$thisSeason and year=$thisYear]/course"
>
>
> 3. I can't use a template match with a VariableReference
> (student name), but I can't create a separate template for
> every case either (too many
> students)
>
> Example:
> <xsl:apply-templates
> select="//schedule[@username=$thisUser]/semester"/>
> ...
> <xsl:template match="//schedule[@username=$thisUser]/semester">
> ...
> </xsl:template>
>
Try using modes:
<xsl:apply-templates
select="//schedule[@username=$thisUser]/semester"
mode="thisUser"/>
<xsl:template match="schedule" mode="thisUser">...
Michael Kay
Software AG
home: Michael.H.Kay@ntlworld.com
work: Michael.Kay@softwareag.com
> Results: invalid XSL
>
> ---------------------
> schedule.xml
> ---------------------
> <schedules>
>
> <schedule username="tommy">
>
> <semester>
> <season>fall</season>
> <year>2002</year>
>
> <course>
> <title>Calc 1</title>
> <desc>...</desc>
> </course>
>
> <course>
> <title>Gym</title>
> <desc>...</desc>
> </course>
>
> </semester>
>
> </schedule>
>
> </schedules>
> --------------------
> - can be 1 to many <schedule>
> - can be 1 to many <semester>
> - can be 1 to many <course>
> --------------------
>
> I want to template match to the level of <semester> so I'm
> only processing at that level to print out the course info
> and if the <schedule> username attribute is not found, it
> returns "not found."
>
> I tried doing something like:
>
> <xsl:template match="schedule[@username=$thisUser]">
>
> <table>
>
> <xs:apply-templates select="semester[season=$thisSeason and
> year=$thisYear]"/>
>
> </table>
>
> </xsl:template>
>
> <xsl:template match="semester[season=$thisSeason and year=$thisYear]">
> <xsl:for-each select="course">
>
> <tr><td><xsl:value-of select="title"/></td></tr>
>
> </xsl:for-each>
> </xsl:template>
>
> ------
> This obviously fails because you can't have a
> VariableReference in the template match, but this is the gist
> of what I'm trying to accomplish.
>
> Any and all help is appreciated as I try to get my feet wet.
>
>
> Regards,
> _ryan
>
>
> XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
>
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list