How does xsl:apply-templates work exactly and why does it write the name 2 times?

StackOverflow https://stackoverflow.com/questions/18547628

  •  26-06-2022
  •  | 
  •  

Вопрос

I am using http://www.freeformatter.com/xsl-transformer.html. Here is my XML document:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="listacd_es1.xslt"?>

<listacd>
    <artista>
        <nome>Stanley Jordan</nome>
        <albums>
            <album>
                <titolo>Magic Touch</titolo>
                <anno>1985</anno>
                <etichetta>Blue Note</etichetta>
            </album>
            <album>
                <titolo>Stolen Moments</titolo>
                <anno>1991</anno>
                <etichetta>Blue Note</etichetta>
            </album>
        </albums>
    </artista>
    <artista>
        <nome>Nick Drake</nome>
        <albums>
            <album>
                <titolo>Pink Moon</titolo>
                <anno>1972</anno>
                <etichetta>Island</etichetta>
            </album>
            <album>
                <titolo>Bryter Layter</titolo>
                <anno>1970</anno>
                <etichetta>Island</etichetta>
            </album>
            <album>
                <titolo>Five leaves left</titolo>
                <anno>1970</anno>
                <etichetta>Island</etichetta>
            </album>
        </albums>
    </artista>
    <artista>
        <nome>Jeff Buckley</nome>
        <albums>
            <album>
                <titolo>Grace</titolo>
                <anno>1994</anno>
                <etichetta>Columbia</etichetta>
            </album>
            <album>
                <titolo>Mistery white boy</titolo>
                <anno>2000</anno>
                <etichetta>Columbia</etichetta>
            </album>
        </albums>
    </artista>
    <artista>
        <nome>Joe Satriani</nome>
        <albums>
            <album>
                <titolo>Surfing with the alien</titolo>
                <anno>1987</anno>
                <etichetta>Epic</etichetta>
            </album>
            <album>
                <titolo>Not of this earth</titolo>
                <anno>1988</anno>
                <etichetta>Relativity</etichetta>
            </album>
        </albums>
    </artista>
</listacd>

Here is the XSLT file:

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

    <xsl:template match="/">
        <html>
            <xsl:apply-templates />
        </html>
    </xsl:template>

    <xsl:template match="artista">
        <b>
            <xsl:value-of select="nome" /> :
        </b>
        <xsl:apply-templates />
        <br />
        <br />
    </xsl:template>

    <xsl:template match="album">
        <xsl:value-of select="titolo" />
    </xsl:template>

</xsl:stylesheet>

And here is the result:

<?xml version="1.0" encoding="UTF-8"?>
<html>
  <b>Stanley Jordan :</b>
  Stanley JordanMagic TouchStolen Moments
  <br />
  <br />
  <b>Nick Drake :</b>
  Nick DrakePink MoonBryter LayterFive leaves left
  <br />
  <br />
  <b>Jeff Buckley :</b>
  Jeff BuckleyGraceMistery white boy
  <br />
  <br />
  <b>Joe Satriani :</b>
  Joe SatrianiSurfing with the alienNot of this earth
  <br />
  <br />
</html>

I know the result is not very pretty, I don't care much, but I don't understand why the name of the artist gets written 2 times. What do I have to do to make the name appear only once for every artist?

Это было полезно?

Решение

This is partial to do with XSLT's built-in templates. These are templates that are used when it can't find a specific template to match a node in your stylesheet. The built-in templates will output the text of any text node is matches, otherwise it will simply skip over the node and carry on processing its children.

The issue arises because of this template

<xsl:template match="artista">
    <b>
        <xsl:value-of select="nome" /> :
    </b>
    <xsl:apply-templates />
    <br />
    <br />
</xsl:template>

In particular, the line <xsl:apply-templates />. This will look for templates that match the child nodes of the current artista element, which in your case are nome and albums, neither of which have matching templates in your XSLT. Thus the built-in templates apply, and in the case of the nome element, the text within it will be output, which is where the duplicate text comes from.

There are two possible, simple, solutions. Firstly, you can this template to your XSLT to match nome in your XSLT, and ignore it, to prevent the built-in template applying:

 <xsl:template match="nome" />

The second solution is to remove the current <xsl:value-of select="." /> from the artista template, and instead have a template matching nome that outputs the value there. Try this XSLT as an example of this

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <xsl:apply-templates />
        </html>
    </xsl:template>

    <xsl:template match="artista">
        <xsl:apply-templates />
        <br />
        <br />
    </xsl:template>

    <xsl:template match="album">
        <xsl:value-of select="titolo" />
    </xsl:template>

    <xsl:template match="nome">
        <b>
            <xsl:value-of select="." /> :
        </b>
   </xsl:template>
</xsl:stylesheet>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top