ChickSentMeHighE
ChickSentMeHighE

Reputation: 1706

XSLT Unexpected repeated text

I am creating a html page with xslt to format my xml into a html page, however I am getting a value repeated and I can't find why, below are my xsl, xml, and html. I have indicated where my repeat value occurs directly below, Thanks for everyone's help!

<fieldset>
    <legend>Joys of a MAD man</legend><ol> 
            Joys of a MAD man *********** Why is the title repeated? ************
           <li>Slow Moving<a href="./Music/Splintz - Joys of a MAD Man/Slow Moving.mp3"> 
          [Download]
          </a></li> 
</ol></fieldset> 

My XML

<albums>
    <album>
        <title>Joys of a MAD man</title>
        <track>Slow Moving</track>
    </album>
    <album>
        <title>Single</title>
        <track>None</track>
    </album>
</albums>

and finally my xsl

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="album">
        <fieldset>
            <legend><xsl:value-of select="title/text()" /></legend>
            <ol>
                <xsl:apply-templates />
            </ol>
        </fieldset>
    </xsl:template>

        <xsl:template match="track">        
           <li>
               <xsl:value-of select="text()" />
               <a>
                   <xsl:attribute name="href">
                   <xsl:text>./Music/Splintz - Joys of a MAD Man/</xsl:text>
                   <xsl:value-of select="text()"/>
                   <xsl:text>.mp3</xsl:text>
               </xsl:attribute>
               [Download]
               </a>
           </li>
         </xsl:template>
</xsl:stylesheet>

Upvotes: 2

Views: 615

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

As pointed out by other people, the default XSLT processing is selecting for execution the built-in XSLT templates and this results in outputting text nodes.

As your code isn't relying on the XSLT built-in template for a text node, the simplest possible solution is to override this template with one that has no body.

Add the following to your code:

 <xsl:template match="text()"/>

Now your full code becomes this:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="album">
        <fieldset>
            <legend>
                <xsl:value-of select="title/text()" />
            </legend>
            <ol>
                <xsl:apply-templates />
            </ol>
        </fieldset>
    </xsl:template>

    <xsl:template match="track">
        <li>
            <xsl:value-of select="text()" />
            <a>
                <xsl:attribute name="href">
                    <xsl:text>./Music/Splintz - Joys of a MAD Man/</xsl:text>
                    <xsl:value-of select="text()"/>
                    <xsl:text>.mp3</xsl:text>
                </xsl:attribute> 
                    [Download]               
            </a>
        </li>
    </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

and the result doesn't contain the unwanted repeated text:

<fieldset>
   <legend>Joys of a MAD man</legend>
   <ol>
      <li>Slow Moving<a href="./Music/Splintz - Joys of a MAD Man/Slow Moving.mp3">
                [Download]
            </a>
      </li>
   </ol>
</fieldset>
<fieldset>
   <legend>Single</legend>
   <ol>
      <li>None<a href="./Music/Splintz - Joys of a MAD Man/None.mp3">
                [Download]
            </a>
      </li>
   </ol>
</fieldset>

Upvotes: 1

Mads Hansen
Mads Hansen

Reputation: 66714

There are built-in default template rules that copy text to the result document.

<xsl:apply-templates/> is short for <xsl:apply-templates select="child::node()"/>.

You used xsl:apply-templates inside the template match for album. When you are "standing" on the album element, title is one of the child nodes that get processed.

The built-in template matched title output it's text() "Joys of a MAD man" the second time.

There are a number of ways to prevent the title text from being output the second time. You could:

  • add an empty template matching title to your stylesheet to prevent the built-in template from matching:
    • <xsl:template match="title"/>
  • exclude title from your apply-templates:
    • <xsl:apply-templates select="node()[not(self::title)]"/>
  • only apply-templates to the track child elements:
    • <xsl:apply-templates select="track"/>

Upvotes: 2

Michael-O
Michael-O

Reputation: 18430

Because you apply <xsl:apply-templates /> to the same context name album as you do the value-of above. It strips all text nodes from all descendants. Say explicitly <xsl:apply-templates match="track" />.

Upvotes: 1

Related Questions