Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old March 7th, 2007, 06:05 PM
Authorized User
 
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
Default Conditionally display text

I'm a newbie and I'm having trouble with conditionally displaying text. This is what I'm working with:

XML FILE:
Code:
<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:
Code:
<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?

 
Old March 7th, 2007, 07:19 PM
Friend of Wrox
 
Join Date: Jul 2006
Posts: 430
Thanks: 28
Thanked 5 Times in 5 Posts
Send a message via Yahoo to bonekrusher
Default

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
 
Old March 7th, 2007, 07:42 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

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
 
Old March 7th, 2007, 08:33 PM
Authorized User
 
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
Default

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:
Code:
<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:
Code:
<?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

 
Old March 8th, 2007, 07:08 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

>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
 
Old March 8th, 2007, 12:19 PM
Authorized User
 
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
Default

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:

Code:
<?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>



    </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:
Code:
   ...

   <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

 
Old March 9th, 2007, 11:02 AM
Authorized User
 
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
Default

does anyone have any thoughts on this?






Similar Threads
Thread Thread Starter Forum Replies Last Post
conditionally setting variable ewel Beginning PHP 2 December 13th, 2007 07:39 PM
conditionally selecting buttons R4addZ Visual Basic 2005 Basics 3 July 13th, 2007 04:26 PM
change styles of text Box conditionally using CSS toshi CSS Cascading Style Sheets 1 May 26th, 2006 08:49 AM
Conditionally display text object leo_vinay Crystal Reports 1 April 18th, 2006 07:22 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.