|
Subject:
|
Conditionally display text
|
|
Posted By:
|
mister_mister
|
Post Date:
|
3/7/2007 5:05:32 PM
|
I'm a newbie and I'm having trouble with conditionally displaying text. This is what I'm working with:
XML FILE:
<root>
<item>
<type>Apple</type>
<price>$0.50</price>
</item>
<item>
<type>Orange</type>
<price>$1.00</price>
</item>
<item>
<type>Apple</type>
<price>$0.75</price>
</item>
</root> I've got a simple XSLT that displays the XML like this:
Apple Prices: $0.50 $0.75
Orange Prices: $1.00
But my problem occurs when there aren't any Oranges in my XML file, but my XSLT still displays the text "Orange Prices:". Here's an example of my problem:
XML FILE:
<root>
<item>
<type>Apple</type>
<price>$0.50</price>
</item>
<item>
<type>Apple</type>
<price>$0.75</price>
</item>
</root> With the same XSLT I get this:
Apple Prices: $0.50 $0.75
Orange Prices:
But what I want to really get is just this:
Apple Prices: $0.50 $0.75
How can I not display "Orange Prices" if there aren't any oranges in my XML file? Sorry, I'm a newbie and am lost as how to even approach this.
Thanks, Steve
PS - This is a simplified example of what my problem is. My XSLT is pretty long and uses different fields so that is why i didn't post it here. Do you know of how to write an XSLT to display this correctly?
|
|
Reply By:
|
bonekrusher
|
Reply Date:
|
3/7/2007 6:19:22 PM
|
You have several ways to get your desired results:
<xsl:choose> <xsl:when test="type = 'oranges'"> do something.... </xsl:when> </xsl:choose>
or
<xsl:if test="type"> do something
|
|
Reply By:
|
mhkay
|
Reply Date:
|
3/7/2007 6:42:37 PM
|
It's a shame you haven't shown any code, because when you're beginning, getting feedback on your code can be really useful - even if it actually works.
If you know when you write the stylesheet what kinds of fruit you might encounter, the logic is
<xsl:if test="item[type='Apple']"> <h1>Apples</h1> <xsl:apply-templates select="item[type='Apple']"/> </xsl:if> <xsl:if test="item[type='Orange']"> <h1>Oranges</h1> <xsl:apply-templates select="item[type='Orange']"/> </xsl:if>
If you don't know what kinds of fruit there might be, you have a grouping problem. In XSLT 2.0 that can be tackled easily with the for-each-group instruction. In XSLT 1.0 it's surprisingly hard: go to http://www.jenitennison.com/xslt/grouping for a survey of techniques, or look in your favourite Wrox textbook for "Muenchian grouping".
Michael Kay http://www.saxonica.com/ Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|
Reply By:
|
mister_mister
|
Reply Date:
|
3/7/2007 7:33:50 PM
|
thanks for your help, however i think i might have been too simplistic in describing my problem. i also forgot to mention that my XSLT uses a for-each loop. here's what my real XML and XSLT looks like:
it's essentially the same simplified scenario as above, except instead of "Apples" and "Oranges", we're categorizing items by "Diagnostic" and "Educational". And instead of display the fruit "Price", we're displaying a "Link" with a bullet.
XML FILE:
<Collection>
<Content>
<Title>Medicine Reactions</Title>
<Html>
<root>
<ReferenceCategory>Diagnostic</ReferenceCategory>
<ExternalLink>http://some-link.com</ExternalLink>
</root>
</Html>
</Content>
<Content>
<Title>Healthcare Plans</Title>
<Html>
<root>
<ReferenceCategory>Educational</ReferenceCategory>
<ExternalLink>http://another-url.com</ExternalLink>
</root>
</Html>
</Content>
<Content>
<Title>Cancer Treatment Options</Title>
<Html>
<root>
<ReferenceCategory>Education</ReferenceCategory>
<ExternalLink>http://one-more-link.com</ExternalLink>
</root>
</Html>
</Content>
</Collection> And my XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<table border="0" cellspacing="0" cellpadding="0">
<xsl:call-template name="category">
<xsl:with-param name="categoryname">Clinical Organizations</xsl:with-param>
</xsl:call-template>
<xsl:for-each select="Collection/Content">
<xsl:if test="Html/root/ReferenceCategory = 'Clinical Organizations'">
<xsl:call-template name="display">
<xsl:with-param name="link" select="Html/root/ExternalLink"/>
<xsl:with-param name="title" select="Title"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
<xsl:call-template name="category">
<xsl:with-param name="categoryname">Diagnostic</xsl:with-param>
</xsl:call-template>
<xsl:for-each select="Collection/Content">
<xsl:if test="Html/root/ReferenceCategory = 'Diagnostic'">
<xsl:call-template name="display">
<xsl:with-param name="link" select="Html/root/ExternalLink"/>
<xsl:with-param name="title" select="Title"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="display">
<xsl:param name="link" select="Html/root/ExternalLink"/>
<xsl:param name="title" select="Title"/>
<tr>
<td valign="top">
<img src="http://172.16.2.33/images/global/bullet.gif" style="padding: 7px 8px 0px 4px;" />
</td>
<td>
<a href="$link" target="_blank">
<xsl:value-of select="$title"/>
</a>
<br />
</td>
</tr>
</xsl:template>
<xsl:template name="category">
<xsl:param name="categoryname" select="categoryname"/>
<tr>
<td valign="top" colspan="2">
<strong style="color:#333333;">
<xsl:value-of select="$categoryname"/>
</strong>
<br />
</td>
</tr>
</xsl:template>
</xsl:stylesheet> Thanks again for your help - I'm drowning! Steve
|
|
Reply By:
|
mhkay
|
Reply Date:
|
3/8/2007 6:08:02 AM
|
>it's essentially the same simplified scenario as above,
and it's essentially the same solution: just wrap an xsl:if around the relevant code. I can't quite see where the problem is.
When you do this:
<xsl:call-template name="category"> <xsl:with-param name="categoryname">Clinical Organizations</xsl:with-param> </xsl:call-template> <xsl:for-each select="Collection/Content"> <xsl:if test="Html/root/ReferenceCategory = 'Clinical Organizations'">
you obviously need to avoid the call-template on category if there isn't anything in that category.
Incidentally the construct
<xsl:for-each select="X"> <xsl:if test="Y"> ... </xsl:if> </xsl:for-each>
can always be replaced by
<xsl:for-each select="X[Y]"> ... </xsl:for-each>
The fact that this code appears twice with only one string literal differing suggests some scope for refactoring:
<xsl:call-template name="category"> <xsl:with-param name="categoryname">Clinical Organizations</xsl:with-param> </xsl:call-template>
<xsl:for-each select="Collection/Content"> <xsl:if test="Html/root/ReferenceCategory = 'Clinical Organizations'"> <xsl:call-template name="display"> <xsl:with-param name="link" select="Html/root/ExternalLink"/> <xsl:with-param name="title" select="Title"/> </xsl:call-template> </xsl:if> </xsl:for-each>
A general observation, you're trying to write this as if template rules and apply-templates didn't exist. That way, you're avoiding one of the most powerful features of the language, some would say its essential core. It's like using Java and avoiding objects.
Michael Kay http://www.saxonica.com/ Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|
Reply By:
|
mister_mister
|
Reply Date:
|
3/8/2007 11:19:56 AM
|
thanks michael - i've got my XSLT to behave like i want, but am curious as to your suggestions for improvement. like i mentioned, im a newbie at XSLT so please forgive my dumb questions. the following is my XSLT that works correctly:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<table border="0" cellspacing="0" cellpadding="0">
<xsl:if test="Collection/Content[Html/root/ReferenceCategory='Clinical Organizations']">
<xsl:call-template name="category">
<xsl:with-param name="categoryname">Clinical Organizations</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:for-each select="Collection/Content">
<xsl:if test="Html/root/ReferenceCategory = 'Clinical Organizations'">
<xsl:call-template name="display">
<xsl:with-param name="link" select="Html/root/ExternalLink"/>
<xsl:with-param name="title" select="Title"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
<!-- Duplicate blocks of code like above for other Categories -->
</table>
</xsl:template>
<xsl:template name="display">
<xsl:param name="link" select="Html/root/ExternalLink"/>
<xsl:param name="title" select="Title"/>
<tr>
<td valign="top">
<img src="http://172.16.2.33/images/global/bullet.gif" style="padding: 7px 8px 0px 4px;" />
</td>
<td>
<a href="$link" target="_blank">
<xsl:value-of select="$title"/>
</a>
<br />
</td>
</tr>
</xsl:template>
<xsl:template name="category">
<xsl:param name="categoryname" select="categoryname"/>
<tr>
<td valign="top" colspan="2">
<strong style="color:#333333;">
<xsl:value-of select="$categoryname"/>
</strong>
<br />
</td>
</tr>
</xsl:template>
</xsl:stylesheet> im always open to making my code more elegant, and from what you said, i guess it can be improved - but how?
ive tried to use "apply-templates" to print the "ReferenceCategory" title, but it doesn't output any results. this is what ive tried:
...
<xsl:if test="Collection/Content[Html/root/ReferenceCategory='Clinical Organizations']">
<xsl:apply-templates select="ReferenceCategory"/>
</xsl:if>
...
<xsl:template match="ReferenceCategory">
<tr>
<td valign="top" colspan="2">
<strong style="color:#333333;">
<xsl:value-of select="."/>
</strong>
<br />
</td>
</tr>
</xsl:template>
... is using "apply-templates" typically the best approach? should i also use "apply-templates" instead of using a "call-template" to "display"?
thanks, steve
|
|
Reply By:
|
mister_mister
|
Reply Date:
|
3/9/2007 10:02:55 AM
|
does anyone have any thoughts on this?
|