XSLT - count the number of child elements by using XPath

57,550

Your first xsl:when test is incorrect here

<xsl:when test="actor[count(*) &gt; 1]/name">

You are already positioned on an actor element here, so this will be looking for an actor element that is a child of the current actor element, and finding nothing.

You probably just want to do this

<xsl:when test="count(*) &gt; 1">

Alternatively, you could do this

<xsl:when test="*[2]">

i.e, is there an element in the second position (that saves counting all elements, when you only really want to check there is more than one),

Or perhaps you want to check the current actor element has an element other than name?

<xsl:when test="*[not(self::name)]">

As an aside, it might be better to put the test in a template match, rather than use an xsl:choose.

Try this XSLT

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

   <xsl:template match="/">
      <div>
         <xsl:apply-templates select="database/movies/movie"/>
      </div>
   </xsl:template>

   <xsl:template match="movie">
      <xsl:value-of select="concat('Title: ', title)"/>
      <br/>
      <xsl:text>Actors: </xsl:text>
      <xsl:apply-templates select="actors/actor"/>
      <br/>
   </xsl:template>

   <xsl:template match="actor">
      <xsl:value-of select="name"/>
      <br/>
   </xsl:template>

   <xsl:template match="actor[*[2]]">
      <a href="actor_details.php?actorID={@actorID}">
         <xsl:value-of select="name"/>
      </a>
      <br/>
   </xsl:template>
</xsl:stylesheet>

Note that the XSLT processor should match the more specific template first in this instance.

Share:
57,550
Alex
Author by

Alex

Updated on May 05, 2020

Comments

  • Alex
    Alex about 4 years

    I have the following XML file that stores movies and actors details:

    <database
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="movies.xsd">
    
    <movies>
        <movie movieID="1">
            <title>Movie 1</title>
            <actors>
                <actor actorID="1">
                    <name>Bob</name>
                    <age>32</age>
                    <height>182 cm</height>
                </actor>
                <actor actorID="2">
                    <name>Mike</name>
                </actor>
            </actors>
        </movie>
    </movies>
    
    </database>
    

    If the actor element contains more than one child elements (in this case it's name, age and height) then I want to display its name as a hyperlink.

    If, however, the actor element only contains one child element (name), then it should be displayed as plain text.

    XSLT:

    <xsl:template match="/">
        <div>
          <xsl:apply-templates select="database/movies/movie"/>
        </div>
      </xsl:template>
    
      <xsl:template match="movie">
        <xsl:value-of select="concat('Title: ', title)"/>
        <br />
        <xsl:text>Actors: </xsl:text>
        <xsl:apply-templates select="actors/actor" />
        <br />
      </xsl:template>    
    
    <xsl:template match="actor">
        <xsl:choose>
            <xsl:when test="actor[count(*) &gt; 1]/name">
                <a href="actor_details.php?actorID={@actorID}">
                    <xsl:value-of select="name"/>
                </a>
                <br/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="name"/>
                <br/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    

    So in this case Bob should be displayed as a hyperlink, and Mike should be displayed as plain text. However, my page displays both Bob and Mike as plain text.