Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Grouping problem 1

Status
Not open for further replies.

JontyMC

Programmer
Nov 26, 2001
1,276
GB
XML:
Code:
<project>
  <task>
    <name>a</name>
    <type>type1</type>
  </task>
  <task>
    <name>b</name>
    <type>type1</type>
  </task>
  <task>
    <name>c</name>
    <type>type2</type>
  </task>
</project>
I want the output like this:

type1
a
b
type2
c

I thought I could simply look at the previous sibling to and only output a heading if its type is different to the current one.

XSL:
Code:
<xsl:for-each select="project/task">
  <xsl:if test="type!=string(preceding-sibling::type)">
    <h2><xsl:value-of select="type" /></h2>
  </xsl:if>
  <p><xsl:value-of select="TaskName" /></p>
</xsl:for-each>

This doesnt work. How come?
 
first, start by finding objects with a similar type...

then go from there...
... select="project/task[type="type1"] ...
... select="project/task[type="type2"] ...

Then look into ways to get the different types programmatically (well XSL-atically at least ;-))...


then you always have the <xsl:sort> tag...

.......................
I got bored... so here is an example ;-)
sort.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="sort.xsl"?>
<project>
  <task>
    <name>a</name>
    <type>type1</type>
  </task>
  <task>
    <name>b</name>
    <type>type1</type>
  </task>
  <task>
    <name>c</name>
    <type>type2</type>
  </task>
  <task>
    <name>d</name>
    <type>type1</type>
  </task>
  <task>
    <name>e</name>
    <type>type2</type>
  </task>
</project>

sort.xsl
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:template match="/">
    <xsl:for-each select="project/task">
      <xsl:sort select="type"/>
      <xsl:if test="not(preceding-sibling::task/type = type)">
        <xsl:variable name="TYPE" select="type" />
        <b><xsl:value-of select="$TYPE" /></b><br />
        <xsl:for-each select="//project/task[type = $TYPE]">
          <xsl:value-of select="name" /><br />
        </xsl:for-each>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

output:
Code:
[b]type1[/b]
a
b
d
[b]type2[/b]
c
e

Hope This Helps ;-)
-Josh

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Thanks for the reply, it helped me fix my code. This is what I ended up with:

Code:
<xsl:for-each select="project/task">
  <xsl:sort select="type" />
  <xsl:if test="not(preceding-sibling::task/type = type)">
    <b><xsl:value-of select="type" /></b><br />
  </xsl:if>
  <xsl:value-of select="name" /><br />
</xsl:for-each>

But this has left me very confused with the test expression. If you do this:
Code:
<xsl:for-each select="project/task">
  <xsl:sort select="type" />
  <p>
    <xsl:value-of select="preceding-sibling::task/type" />,
    <xsl:value-of select="type" />,
    <xsl:value-of select="preceding-sibling::task/type = type" />
  </p>
</xsl:for-each>

You get:
Code:
,type1,false
type1,type1,true
type1,type1,true
type1,type2,false
type1,type2,true

What gives?
 
That's right... but I used NOT...
The First node has no preceding-sibling...
So it returns false, which not() flips to true...

Now try:
Code:
<xsl:for-each select="project/task">
  <xsl:sort select="type" />
  <p>
    <xsl:value-of select="not(preceding-sibling::task/type)" />,
    <xsl:value-of select="type" />,
    <xsl:value-of select="not(preceding-sibling::task/type = type)" />
  </p>
</xsl:for-each>

You should get:
Code:
true, type1, true
false, type1, false
false, type1, false
false, type2, true
false, type2, false

So instead of saying what you want to find, you basically say what you DON'T want to find...

Hope This Helps,
-Josh

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
What I'm saying is why does
Code:
<xsl:value-of select="preceding-sibling::task/type" />
always return type1?

And why does type1 = type2 equate to true in the last case?
 
Good question...

I dunno... I guess it doesn't matter as long as the functionality works...
maybe it only works when being compared to a value...

....

Ahhh...
It returns all of the nodes before the current...
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:template match="/">
<xsl:for-each select="project/task">
  <xsl:sort select="type" />
  <p>
    <xsl:for-each select="preceding-sibling::task">
      <xsl:value-of select="name" />,
    </xsl:for-each>
  </p>
</xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Code:
a, 
a, b, c, 
a, b, 
a, b, c, d, 
a, b, c, d, e, 
a, b, c, d, e, f, g, h, 
a, b, c, d, e, f, 
a, b, c, d, e, f, g,

It was just defaulting to the first one...

Though, it looks like it returns the unsorted nodes...

Oh well... as long as it works ;-)

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
I see how it works now and it works. Great.

Thanks, I'll give you a star.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top