School Assignment? Project Due Tomorrow? Chat LIVE With A Programming Expert!

Welcome to Dream.In.Code
Become an Expert!

Join 307,146 Programmers for FREE! Get instant access to thousands of experts, tutorials, code snippets, and more! There are 1,743 people online right now. Registration is fast and FREE... Join Now!




Beginner XML / XSLT count() help needed!

 

Beginner XML / XSLT count() help needed!

LuckyPierre

31 Oct, 2009 - 04:33 PM
Post #1

New D.I.C Head
*

Joined: 23 Sep, 2009
Posts: 30

Hi everyone!

I'm quite new to XML and XSLT and am trying to work out how to do the following example:

xml code:

CODE

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

<root>
    <dog>
        <breed>Clumber</breed>
        <name>Bonnie</name>
        <weight>70</weight>
    </dog>    
    <dog>
        <breed>Clumber</breed>
        <name>Presley</name>
        <weight>85</weight>
    </dog>
    <dog>
        <breed>Cocoa</breed>
        <name>Lhasa Apso</name>
        <weight>22</weight>
    </dog>
</root>




XSLT code:

CODE

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


<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
  
<xsl:key name="dogs" match="/root/dog" use="breed"/>

    <xsl:template match="/">
         <html>
             <head> <title>Example02</title></head>
             <body>
                 <table border="1">
                     <tr bgcolor="#9acd32">
                         <th>Breed</th>
                         <th>Number of Dogs</th>
                     </tr>
                     <xsl:for-each select="root/dog[generate-id() = generate-id(key('dogs',breed)[1])]">
                         <xsl:sort select="breed"/>
                         <tr>
                             <th><xsl:value-of select="breed"/></th>
                         </tr>    
                     </xsl:for-each>
                 </table>
             </body>
         </html>
    </xsl:template>
</xsl:stylesheet>



I have written it so that if you open the xml file in explorer you get a table which shoes the different breeds of dogs in the left hand column.

The part that I am unable to do it to fill the right hand column with the number of each breed of dog that is in the xml...

I believe I should use count() somehow but am having trouble working out exactly what to do...

any help would be appreciated.

Thanks!!

(files should be attached too)

User is offlineProfile CardPM
+Quote Post


baavgai

RE: Beginner XML / XSLT Count() Help Needed!

31 Oct, 2009 - 05:25 PM
Post #2

Dreaming Coder
Group Icon

Joined: 16 Oct, 2007
Posts: 4,351



Thanked: 412 times
Dream Kudos: 550
Expert In: C, C++, Java, C#, ASP.NET, PHP, Perl, Python, Oracle, SQL Server, MySql, HTML, JavaScript, Lua, Cheese

My Contributions
You rarely need for-each in XSL. The real trick is a variable and a global xpath.

This should work:
xml

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:key name="dogs" match="/root/dog" use="breed"/>

<xsl:template match="/">
<html>
<head><title>Example02</title></head>
<body>
<table border="1">
<tr bgcolor="#9acd32"><th>Breed</th><th>Number of Dogs</th></tr>
<xsl:apply-templates select="//dog[generate-id() = generate-id(key('dogs',breed)[1])]/breed">
<xsl:sort select="breed"/>
</xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>

<xsl:template match="breed">
<xsl:variable name="breedName" select="text()"/>
<tr>
<td><xsl:value-of select="$breedName"/></td>
<td><xsl:value-of select="count(//dog[breed=$breedName])"/></td>
</tr>
</xsl:template>

</xsl:stylesheet>


User is online!Profile CardPM
+Quote Post

thehat

RE: Beginner XML / XSLT Count() Help Needed!

31 Oct, 2009 - 05:28 PM
Post #3

awake ? web();
Group Icon

Joined: 28 Feb, 2008
Posts: 940



Thanked: 99 times
Dream Kudos: 200
My Contributions
The syntax for this stuff is a bit mind-boggling. You need to count all occurrences of breed, using the current breed in your for loop:

CODE
<td><xsl:value-of select="count(//breed[.=current()/breed])" /></td>


Edit: or Baavgai's solution, which is cleaner!

This post has been edited by thehat: 31 Oct, 2009 - 05:31 PM
User is offlineProfile CardPM
+Quote Post

LuckyPierre

RE: Beginner XML / XSLT Count() Help Needed!

31 Oct, 2009 - 06:40 PM
Post #4

New D.I.C Head
*

Joined: 23 Sep, 2009
Posts: 30

Thanks very much for both the replies.

I am finding the syntax is taking a little getting used to. I've also yet to find a really good reference on the web for xslt so looks like a trip to the book shop tomorrow...

Thanks again!

User is offlineProfile CardPM
+Quote Post

LuckyPierre

RE: Beginner XML / XSLT Count() Help Needed!

1 Nov, 2009 - 08:46 AM
Post #5

New D.I.C Head
*

Joined: 23 Sep, 2009
Posts: 30


Another point about this exercise that I'd like to have a greater understanding of is the following line which is used to select distinct values:

CODE

    //dog[generate-id() = generate-id(key('dogs',breed)[1])]



An explanation is very simple English would be useful.

As far as I can understand it means:


//dog - selects all dog nodes

[] - the code in between these brackets specifies a condition, such as only use the first node

generate-id() - generates a unique id for the node, in this case the node is the current dog node that is being examined to see if it should be selected or not.

key('dogs', breed) - Uses the key names 'dogs' to select all dog nodes which have the same breed as the current node

[1] - in this case this selects the first of the values returned by the key statement

generate(key...) - generates a unique id for the first dog node returned by the key statement...



I'm still having a little trouble understanding this

- won't each dog node be matched with itself in the [generate id = ...] condition?


If anyone can add anything to help me understand then it would be greatly appreciated....

the more verbose the explanation the better!

Cheers!

User is offlineProfile CardPM
+Quote Post

LuckyPierre

RE: Beginner XML / XSLT Count() Help Needed!

1 Nov, 2009 - 09:37 AM
Post #6

New D.I.C Head
*

Joined: 23 Sep, 2009
Posts: 30

Also..

thanks for your reply - baavgai - your code looks a lot more tidy than mine..

Your code doesn't seem to sort on breed any more though?

Any idea why?

Cheers
User is offlineProfile CardPM
+Quote Post

LuckyPierre

RE: Beginner XML / XSLT Count() Help Needed!

1 Nov, 2009 - 03:26 PM
Post #7

New D.I.C Head
*

Joined: 23 Sep, 2009
Posts: 30

ok, found out what was happening with the sorting problem..

Still wondering about the distinct select though...
User is offlineProfile CardPM
+Quote Post

baavgai

RE: Beginner XML / XSLT Count() Help Needed!

1 Nov, 2009 - 04:26 PM
Post #8

Dreaming Coder
Group Icon

Joined: 16 Oct, 2007
Posts: 4,351



Thanked: 412 times
Dream Kudos: 550
Expert In: C, C++, Java, C#, ASP.NET, PHP, Perl, Python, Oracle, SQL Server, MySql, HTML, JavaScript, Lua, Cheese

My Contributions
I would suggest Dave Pawson's excellent XSL site: http://www.dpawson.co.uk/xsl/sect2/sect21.html

The select distinct thing is kind all of a trick. You essentially say "give me all nodes that match this" and take the first one. The generate-id is a way of caching the results of that kind of request. It's not actually required, it just speeds things up. For small lists you can use a simpler form.

Here is another way to do the trick. Note that you ask for all the nodes. The template then asks for all the nodes of a type. If the current node is the first of it's kind, process it.

xml

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

<xsl:template match="/">
<html>
<head><title>Example02</title></head>
<body>
<table border="1">
<tr bgcolor="#9acd32"><th>Breed</th><th>Number of Dogs</th></tr>
<xsl:apply-templates select="//breed"><xsl:sort select="breed"/></xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>

<xsl:template match="breed">
<xsl:variable name="thisDog" select=".."/>
<xsl:variable name="allDogSameBreed" select="//dog[breed=$thisDog/breed]"/>
<xsl:if test="$thisDog=$allDogSameBreed[1]">
<tr>
<td><xsl:value-of select="$thisDog/breed"/></td>
<td><xsl:value-of select="count($allDogSameBreed)"/></td>
</tr>
</xsl:if>
</xsl:template>

</xsl:stylesheet>


User is online!Profile CardPM
+Quote Post

Fast ReplyReply to this topicStart new topic

Time is now: 11/21/09 03:50PM

Live Help!

Be Social

Dream.In.Code RSS Feed Dream.In.Code LinkedIn Group Follow Us On Twitter Fan Us On Facebook

Tutorials

Programming

Web Development

Reference Sheets

Code Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month