简体   繁体   中英

XSLT - count the number of child elements by using XPath

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.

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]">

ie, 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM