koshi18
koshi18

Reputation: 53

xpath for counting childnodes with the same tag name

i need to find all the book and if the book has more than one author,write the first authors name and "et al" after that name.Below is my code and first book prints with "J.K. Rowling et al" but its not working for the second book.

this is the xml code

 <bookstore>
 <book>
 <title category="fiction">Harry Potter</title>
 <author>J. K. Rowling</author>
<author>sxdgfds</author>
<publisher>Bloomsbury</publisher>
 <year>2005</year>
 <price>29.99</price>
 </book>
 <book>
 <title category="fiction">The Vampire Diaries</title>
 <author>L.J. Smith</author>
 <author>sdgsdgsdgdsg</author>
<publisher>Bloomsbury</publisher>
 <year>2004</year>
 <price>25.99</price>
 </book>
 <book>
 <title category="fiction">The DaVinci Code</title>
 <author>Dan Brown</author>
<publisher>Bloomsbury</publisher>
 <year>2002</year>
 <price>35.99</price>
 </book>

this is the xslt code

 <xsl:for-each select="//book[30 >price]">

    <xsl:if test="title[@category='fiction']">

             <span style="color:blue;font-weight:bold"><xsl:value-of select="title"/></span><br />
             <xsl:choose>
                <xsl:when test="count(./author)>1">
                    <span style="color:red;font-style:italic"><xsl:value-of select="author"/></span>
                    <span style="color:red;font-style:italic"> et al</span><br />
                </xsl:when>
                <xsl:otherwise>
                    <span style="color:red;font-style:italic"><xsl:value-of select="author"/></span><br />
                </xsl:otherwise>
            </xsl:choose>
             <span><xsl:value-of select="price"/></span><br />

    </xsl:if>

  </xsl:for-each>

i was trying to count how many authors are there but seems like i'm having a problem with the path that i have given to the count function.Any help would be appreciated.

Upvotes: 0

Views: 496

Answers (1)

Tomalak
Tomalak

Reputation: 338118

Your code seems to be okay, but the same thing can be expressed simpler.

<xsl:for-each select="//book[price &lt; 30]">
    <xsl:if test="title[@category='fiction']">
        <span style="color:blue;font-weight:bold"><xsl:value-of select="title"/></span><br />
        <span style="color:red;font-style:italic"><xsl:value-of select="author[1]" /></span>
        <xsl:if test="author[2]">
            <span style="color:red;font-style:italic"> et al</span>
        </xsl:if>
        <br />
        <span><xsl:value-of select="price"/></span><br />
    </xsl:if>
</xsl:for-each>

The above is shorter than your code, but it's not very elegant. This is better.

<xsl:template match="/">
  <xsl:apply-templates select="//book[price &lt; 30 and @category='fiction']" />
</xsl:template>

<xsl:template match="book">
  <div class="book">
    <div class="title"><xsl:value-of select="title"/></div>
    <div class="author">
      <xsl:value-of select="author[1]" /><xsl:if test="author[2]"> et al</xsl:if>
    </div>
    <div class="price"><xsl:value-of select="price"/></div>
  </div>
</xsl:template>
  • Write generic templates that can display every book, like this one.
  • Use them via <xsl:apply-templates> instead of repeating yourself with <xsl:for-each>.
  • Use CSS to style the output. Inline styles are ugly.

Upvotes: 1

Related Questions