Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
| Search | Today's Posts | Mark Forums Read
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
  #1 (permalink)  
Old July 22nd, 2005, 09:41 AM
Registered User
 
Join Date: Jul 2005
Location: , , .
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default Empty tags in resulting html?

Hello all-

I am studying the examples in Tennison's "Beginning XSLT," as I am simply trying to transform XML to HTML. My question is: How do you avoid having empty tags in the resulting html? In this example, the html output is rife with empty[list] tags ([list]</ul>) when the source document does not contain anything in the "<castlist>" node.

Here's a snippet of the HTML output. Notice the empty <ul class="castlist"></ul> tags:

<div>
<p>
<span class="date">2001-07-05T19:00:00</span>
<br>
<span class="title">QuestionOfSport</span>
<br>
</p>
<ul class="castlist"></ul>
</div>
<div>
<p>
<span class="date">2001-07-05T19:30:00</span>
<br>
<span class="title">EastEnders</span>
<br>
        Mark's health scare forces him to reconsider his future with Lisa,
        while Jamie is torn between Sonia and Zoe.
      </p>
<ul class="castlist">
<li>
<span class="character">Zoe Slater</span><span class="actor">Michelle Ryan</span>
</li>
<li>
<span class="character">Jamie Mitchell</span><span class="actor">Jack Ryder</span>
</li>
<li>
<span class="character">Sonia Jackson</span><span class="actor">Natalie Cassidy</span>
</li>
</ul>
</div>
<div>
<p>
<span class="date">2001-07-05T20:00:00</span>
<br>
<span class="title"></span>
<br>
</p>
<ul class="castlist"></ul>
</div>
<div>
<p>
<span class="date">2001-07-05T20:45:00</span>
<br>
<span class="title">Lottery</span>
<br>
</p>
<ul class="castlist"></ul>
</div>

Other than writing a bunch of ugly <xsl:if> statements, is there a way to avoid printing out html tags that ultimately will be empty? I can predict that this problem would get worse if you had literal text you had to print out inside those[list] tags (i.e.[list]Cast List:</ul>). That would be really ugly, plus it's just a waste of bandwidth to print out all those empty html tags.

XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?>
<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xsl:version="1.0">
<head>
  <title>TV Guide</title>
  <link rel="stylesheet" href="TVGuide.css" />
  <script type="text/javascript">
    function toggle(element) {
      if (element.style.display == 'none') {
        element.style.display = 'block';
      } else {
        element.style.display = 'none';
      }
    }
  </script>
</head>

<body>
  <h1>TV Guide</h1>
  <xsl:for-each select="/TVGuide/Channel">
    <h2 class="channel"><xsl:value-of select="Name" /></h2>
    <xsl:for-each select="Program">
      <div>
        <p>
          <span class="date"><xsl:value-of select="Start" /></span><br />
          <span class="title"><xsl:value-of select="Series" /></span><br />
          <xsl:value-of select="Description" />
        </p>
        <ul class="castlist">
          <xsl:for-each select="CastList/CastMember">
            <li>
              <span class="character">
                <xsl:value-of select="Character" />
              </span>
              <span class="actor">
                <xsl:value-of select="Actor" />
              </span>
            </li>
          </xsl:for-each>
        </ul>
      </div>
    </xsl:for-each>
  </xsl:for-each>
</body>
</html>

XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="TVGuide3.xsl"?>
<TVGuide start="2001-07-05" end="2001-07-05">
  <Channel>
    <Name>BBC1</Name>
    <Program>
      <Start>2001-07-05T19:00:00</Start>
      <Duration>PT30M</Duration>
      <Series>QuestionOfSport</Series>
      <Title></Title>
    </Program>
    <Program rating="5" flag="favorite">
      <Start>2001-07-05T19:30:00</Start>
      <Duration>PT30M</Duration>
      <Series>EastEnders</Series>
      <Title></Title>
      <Description>
        Mark's health scare forces him to reconsider his future with Lisa,
        while Jamie is torn between Sonia and Zoe.
      </Description>
      <CastList>
        <CastMember>
          <Character><Name>Zoe Slater</Name></Character>
          <Actor><Name>Michelle Ryan</Name></Actor>
        </CastMember>
        <CastMember>
          <Character><Name>Jamie Mitchell</Name></Character>
          <Actor><Name>Jack Ryder</Name></Actor>
        </CastMember>
        <CastMember>
          <Character><Name>Sonia Jackson</Name></Character>
          <Actor><Name>Natalie Cassidy</Name></Actor>
        </CastMember>
      </CastList>
      <Writers>
        <Writer><Name>Nick Saltrese</Name></Writer>
        <Writer><Name>Julie Wassmer</Name></Writer>
      </Writers>
      <Director><Name>Stewart Edwards</Name></Director>
      <Producer><Name>Emma Turner</Name></Producer>
    </Program>
    <Program type="documentary">
      <Start>2001-07-05T20:00:00</Start>
      <Duration>PT45M</Duration>
      <Series></Series>
      <Title>Get Real with Casualty</Title>
    </Program>
    <Program>
      <Start>2001-07-05T20:45:00</Start>
      <Duration>PT45M</Duration>
      <Series>Lottery</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T21:30:00</Start>
      <Duration>PT1H</Duration>
      <Series>Panorama</Series>
      <Title></Title>
    </Program>
  </Channel>
  <Channel>
    <Name>BBC2</Name>
    <Program>
      <Start>2001-07-05T19:00:00</Start>
      <Duration>PT1H</Duration>
      <Series>Snooker</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T20:00:00</Start>
      <Duration>PT1H</Duration>
      <Series>HomeFront</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T21:00:00</Start>
      <Duration>PT50M</Duration>
      <Series>WildAfrica</Series>
      <Title></Title>
    </Program>
    <Program flag="interesting">
      <Start>2001-07-05T21:50:00</Start>
      <Duration>PT40M</Duration>
      <Series>Taboo</Series>
      <Title>Nakedness</Title>
    </Program>
  </Channel>
  <Channel>
    <Name>ITV</Name>
    <Program>
      <Start>2001-07-05T19:00:00</Start>
      <Duration>PT30M</Duration>
      <Series>Emmerdale</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T19:30:00</Start>
      <Duration>PT30M</Duration>
      <Series>CoronationStreet</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T20:00:00</Start>
      <Duration>PT1H</Duration>
      <Series>Millionaire</Series>
      <Title></Title>
    </Program>
    <Program type="drama">
      <Start>2001-07-05T21:00:00</Start>
      <Duration>PT2H</Duration>
      <Series></Series>
      <Title>Hot Money</Title>
    </Program>
  </Channel>
  <Channel>
    <Name>Channel 4</Name>
    <Program>
      <Start>2001-07-05T19:00:00</Start>
      <Duration>PT55M</Duration>
      <Series>Channel4News</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T19:55:00</Start>
      <Duration>PT5M</Duration>
      <Series>SlotArt</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T20:00:00</Start>
      <Duration>PT30M</Duration>
      <Series>Brookside</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T20:30:00</Start>
      <Duration>PT30M</Duration>
      <Series>Brookside</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T21:00:00</Start>
      <Duration>PT1H</Duration>
      <Series>Swallow</Series>
      <Title></Title>
    </Program>
    <Program flag="favorite">
      <Start>2001-07-05T22:00:00</Start>
      <Duration>PT1H</Duration>
      <Series>AllyMcBeal</Series>
      <Title></Title>
    </Program>
  </Channel>
  <Channel>
    <Name>Channel 5</Name>
    <Program>
      <Start>2001-07-05T19:00:00</Start>
      <Duration>PT30M</Duration>
      <Series>MovieChartShow</Series>
      <Title></Title>
    </Program>
    <Program>
      <Start>2001-07-05T19:30:00</Start>
      <Duration>PT30M</Duration>
      <Series>FiveNews</Series>
      <Title></Title>
    </Program>
    <Program type="entertainment">
      <Start>2001-07-05T20:00:00</Start>
      <Duration>PT1H</Duration>
      <Series></Series>
      <Title>The World's Worst Drivers Caught On Tape</Title>
    </Program>
    <Program type="film">
      <Start>2001-07-05T21:00:00</Start>
      <Duration>PT1H55M</Duration>
      <Series></Series>
      <Title>Black and White</Title>
    </Program>
  </Channel>
</TVGuide>
  #2 (permalink)  
Old July 22nd, 2005, 02:37 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

The only way to avoid generating an empty ul element is to avoid generating it. Change

        <ul class="castlist">
          <xsl:for-each select="CastList/CastMember">
            <li>
              <span class="character">
                <xsl:value-of select="Character" />
              </span>
              <span class="actor">
                <xsl:value-of select="Actor" />
              </span>
            </li>
          </xsl:for-each>
        </ul>


to

<xsl:if test="CastList/CastMember">
  [list]
    <xsl:for-each ....>

etc.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
  #3 (permalink)  
Old July 22nd, 2005, 02:50 PM
Registered User
 
Join Date: Jul 2005
Location: , , .
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Dear Mr. Kay-
Thanks so much for the quick reply, but I've been doing a lot of research on how to use the "push" form instead of the "pull" form of stylesheets (of course, the Tennison example is of the pull variety but I'm trying to refactor it). In my research, I have found that it is apparently considered very "bad form" to use conditionals, value-of, for-each, or anything else that seems like a "normal" thing to do in a procedural language like PHP. Instead, one is supposed to use <apply-templates/>.

So is there any way to avoid having to write <xsl:if> for every single node if you don't know from the beginning which nodes of the input XML will be blank and which won't? It seems like a waste to have to put conditionals around every single node. Is there any way to declare once and for all that you don't want to output anything for empty input nodes?

Again, I'm looking for the concise and elegant (some would say "traditional push") way of doing my xsl files, and I want to make sure there isn't a way to accomplish dealing with empty tags without using <xsl:if>, since that's a procedural tag and apparently one isn't supposed to use procedural code in xslt.

  #4 (permalink)  
Old July 22nd, 2005, 03:14 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Sure, you can rewrite this logic using template rules something like this:

<xsl:template match="Channel">
    <h2 class="channel"><xsl:value-of select="Name" /></h2>
    <xsl:apply-templates select="Program"/>
</xsl:template>

<xsl:template match="Program">
      <div>
        <p>
          <span class="date">
            <xsl:value-of select="Start" />
          </span><br />
          <span class="title">
            <xsl:value-of select="Series" />
          </span><br />
          <xsl:value-of select="Description" />
        </p>
        <xsl:apply-templates select="CastList"/>
      </div>
</xsl:template>

<xsl:template match="CastList">[list]
  <xsl:apply-templates select="CastMember"/>
</ul>
</xsl:template>

<xsl:template match="CastList[not(CastMember)]"/>

<xsl:template match="CastMember">
            <li>
              <span class="character">
                <xsl:value-of select="Character" />
              </span>
              <span class="actor">
                <xsl:value-of select="Actor" />
              </span>
            </li>
</xsl:template>

But there's no need to be religious about avoiding xsl:if and xsl:for-each. It's good to know how to use both styles, and in most cases, you will end up using both in combination.


Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
  #5 (permalink)  
Old July 22nd, 2005, 03:20 PM
Registered User
 
Join Date: Jul 2005
Location: , , .
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Wow, that really makes the stylesheet much more complicated, plus one still has to use the apparently verboten "xsl:value-of" as well.

I guess I will stick with the original answer that uses "xsl:if"!

It just makes me wonder why these rules against procedural constructs exist if it seems they are so useful.

Thanks again!

  #6 (permalink)  
Old July 22nd, 2005, 03:57 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

No, it makes the stylesheet much simpler, because it splits it up into separate templates that are very loosely coupled from each other. Reduced coupling = reduced complexity. Try scaling up both solutions to a document with 100 different element types, and you'll see what I mean.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
  #7 (permalink)  
Old July 22nd, 2005, 03:59 PM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Oh, and there's nothing wrong with using xsl:value-of in the right circumstances; and the same is true of xsl:for-each and xsl:if. I gave you the version using template rules because you asked for it, but which solution is better depends on the overall system lifecycle requirements, for example the extent to which components will be reused.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference


Similar Threads
Thread Thread Starter Forum Replies Last Post
Render HTML tags jacksprophet XSLT 1 December 28th, 2006 07:03 PM
empty tags vs. singletons hankshiny XSLT 1 April 9th, 2005 07:37 AM
Saving resulting HTML ashcarrot XSLT 1 August 25th, 2004 05:42 AM
Help! Empty paragraph tags! abq23 PHP How-To 1 June 15th, 2004 08:57 PM
Eliminating HTML TAGs beyondforsaken VB How-To 12 June 12th, 2003 08:00 AM





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