xsl-list
[Top] [All Lists]

RE: [xsl] GROUPING AND KEYS

2009-04-29 06:25:52

Hi Michael,

I would like to thank you for your explanation. It was brillant.

So this bit of code will output only one value when they are the same. 

<xsl:for-each select="foo/shift/partNo[count(. | key('partNo', @num)[=
1]) = 1]">

And this bit will output all values.

 <xsl:for-each select="key('partNo', @num)">

It is a like a one to many relationship or header / values.

Cheers

C


--- On Wed, 29/4/09, 
xsl-list-digest-help(_at_)lists(_dot_)mulberrytech(_dot_)com 
<xsl-list-digest-help(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:

From: xsl-list-digest-help(_at_)lists(_dot_)mulberrytech(_dot_)com 
<xsl-list-digest-help(_at_)lists(_dot_)mulberrytech(_dot_)com>
Subject: xsl-list Digest 29 Apr 2009 05:10:00 -0000 Issue 1832
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Date: Wednesday, 29 April, 2009, 6:10 AM
xsl-list Digest 29 Apr 2009 05:10:00 -0000 Issue 1832

Topics (messages 50662 through 50668):

GROUPING AND KEYS
      50662 by: Cleyton Jordan
      50663 by: Michael Kay

Re: How to cast current-group() ?
      50664 by: Studer Leo
      50665 by: David Carlisle
      50666 by: Studer Leo

Placing an element in a very specific position
      50667 by: Anders.Svensson.sorman.com
      50668 by: G. Ken Holman

Administrivia:

To subscribe to the digest, e-mail:
      <xsl-list-digest-subscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>

To unsubscribe from the digest, e-mail:
      <xsl-list-digest-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>

To post to the list, e-mail:
      <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>


----------------------------------------------------------------------
Date: Tue, 28 Apr 2009 03:21:09 -0700 (PDT)
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
From: Cleyton Jordan <cleytonjordan(_at_)yahoo(_dot_)co(_dot_)uk>
Subject: GROUPING AND KEYS
Message-ID:
<723360(_dot_)94134(_dot_)qm(_at_)web24706(_dot_)mail(_dot_)ird(_dot_)yahoo(_dot_)com>

Hi,

I would like to understand how keys and grouping work in
XSLT and I came ac=
ross a post that might help me. However, I have some
questions regarding th=
e code and would appreciate if someone could shed some
light about sections=
 of the code I do not understand.

"I have Nodes that all have "Shift" data. 
Within these Shifts, I have a Pa=
rt Number.  Now, I want to be able to group and add
together all the data a=
ssociated with a Part Number, regardless of what Shift it
was produced in.=
=20

For example, I want to be able to add together all the
"counts" for part nu=
mber 1. "=20

<foo>
<shift>
  <partNo num=3D"1">
    <data count=3D"2"/>
    <data time=3D"3"/>
  </partNo>
</shift>
<shift>
  <partNo num=3D"1">
    <data count=3D"1"/>
    <data time=3D"5"/>
  </partNo>
</shift>
<shift>
  <partNo num=3D"2">
    <data count=3D"5"/>
    <data time=3D"7"/>
  </partNo>
</shift>
<foo>
1 - Is there a way to visualise in XSLT what this key looks
like?

<xsl:key name=3D"partNo"
match=3D"partNo" use=3D"@num" />

In this statement <xsl:for-each
select=3D"foo/shift/partNo[count(. | key('p=
artNo', @num)[1]) =3D 1]">

we are selecting all partNo nodes where count(. | key(
'partNo', @num)[1]) =
=3D 1]

2 - What does . mean in this expression? the partNo
node?=20

3 - What does | mean?=20

4 - key( 'partNo', @num) - this is the key. Are we
using the current @num a=
ttribute to get all the partNo whose @num =3D 1 then 2
etc...?

5 - )[1]) =3D 1 - Why is it using an array index [1] to get
the first one a=
nd then using =3D 1 ?

I would very much appreciate some feedback and help to
understand this code=
..

CJ

CODE

<xsl:key name=3D"partNo"
match=3D"partNo" use=3D"@num" />

<xsl:template match=3D"/">
    <xsl:for-each
select=3D"foo/shift/partNo[count(. |
key('partNo', @num)[=
1]) =3D 1]">
        <xsl:sort select=3D"@num" />
        Part num: <xsl:value-of
select=3D"@num" />
        <xsl:for-each
select=3D"key('partNo', @num)">
            [<xsl:value-of
select=3D"data/@count" />,
            <xsl:value-of
select=3D"data/@time" />]
        </xsl:for-each>
        <br />

    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>=0A=0A=0A      

------------------------------

Date: Tue, 28 Apr 2009 11:41:57 +0100
To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
From: "Michael Kay" <mike(_at_)saxonica(_dot_)com>
Subject: RE: [xsl] GROUPING AND KEYS
Message-ID:
<5E5B62704D0144729D28C826C55063DD(_at_)Sealion>

It's worth being clear that we're talking here
about the Muenchian method of
grouping in XSLT 1.0. Grouping in XSLT 2.0 is much much
simpler. 

1 - Is there a way to visualise in XSLT what this key
looks like?

<xsl:key name="partNo"
match="partNo" use="@num" />

You can think of it like this: "Each document that
contains partNo elements
has an index, allowing a partNo element to be found quickly
if the value of
its @num attribute is known". For example,
key('partNo', 'P123') returns all
the partNo elements whose @num value is P123.


In this statement <xsl:for-each 
select="foo/shift/partNo[count(. |
key('partNo', @num)[1]) = 1]">

In XSLT 1.0, there is no simple way of asking "$A is
$B", that is, testing
whether two expressions refer to the same node. There are
two common
workarounds to this:

generate-id($A) = generate-id($B)

which relies on the fact that if two nodes have the same
generated ID then
they are the same node, and

count($A|$B) = 1

which relies on the fact that the union of two singleton
sets is a singleton
only if both sets have the same member. In your example,
this is the
expression you are seeing.

Specifically, it's selecting every partNo that is the
first partNo with a
given @num value. That is "." (the partNo being
tested) is the same node as
key('partNo', @num)[1], which is the first partNo
with that @num value.

we are selecting all partNo nodes where count(. | key(

'partNo', @num)[1]) = 1]

2 - What does . mean in this expression? the partNo
node?

Yes, in a predicate "." refers to the node being
tested. 

3 - What does | mean? 

It's a union operator, it forms the union of two sets.

Hope this helps.

Michael Kay
http://www.saxonica.com/

------------------------------

Date: Tue, 28 Apr 2009 17:19:07 +0200
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
From: Studer Leo <leo(_dot_)studer(_at_)me(_dot_)com>
Subject: Re: [xsl] How to cast current-group() ?
Message-id:
<D707EA35-3AA7-42F2-8AB8-C4891670FAD7(_at_)me(_dot_)com>

Dear Michael

thank you for your input. I work with Saxon SA-9.1.0.6
which is not to  
bad with typing and not foolish strict neither...

The problem is the XSLT processor allows me to use this
code snippet

   <xsl:for-each-group select="/results/match"
group-by="team">
          <xsl:copy-of
select="myfn:MakeTableRow(current-grouping- 
key(),current-group())"/>
   </xsl:for-each-group>

with the function only without the type control...

     <xsl:function name="myf:MakeTableRow"
as="schema- 
element(xhtml:tr)">
         <xsl:param name="team"/>   <!--
as="schema-element(res:team)"  
-->
         <xsl:param name="matches"/> 
<!-- as="schema- 
element(res:match)*" -->
         <tr xsl:validation="strict">
            ...
         </tr>
     </xsl:function>

your comment

current-grouping-key() is an atomic value, not an
element. You could
construct an element and give it a type by validating
it, but I  
suspect
that's not what you want to do.

is a solution to the problem, however not the most elegant
one. Type  
casting would be nicer...

I put the whole file in the end.

Thanks again
Leo

<?xml version="1.0"
encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform 
"
     xmlns:xs="http://www.w3.org/2001/XMLSchema";
     xmlns:res="http://results.bla";
     xmlns:myf="http://leostuder.ch/funtions";

     xmlns="http://www.w3.org/1999/xhtml";
     xmlns:xhtml="http://www.w3.org/1999/xhtml";
exclude-result- 
prefixes="xs res myf xhtml">

     <xsl:output method="xhtml"
encoding="ISO-8859-1" indent="yes"
         doctype-public="-//W3C//DTD XHTML 1.0
Strict//EN"
        
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd

"/>

     <xsl:import-schema
namespace="http://results.bla"; schema- 
location="results.xsd"/>

     <xsl:import-schema
namespace="http://www.w3.org/1999/xhtml";
        
schema-location="http://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd

"/>

     <xsl:function name="myf:MakeTableRow"
as="schema- 
element(xhtml:tr)">
         <xsl:param name="team"/>   <!--
as="schema-element(res:team)"  
-->
         <xsl:param name="matches"/> 
<!-- as="schema- 
element(res:match)*" -->
         <tr xsl:validation="strict">
             <td>
                 <xsl:value-of
select="$team"/>
             </td>
             <td>
                 <xsl:value-of
select="count($matches)"/>
             </td>
             <xsl:variable name="won"
                
select="count($matches[res:team[.=$team]/@score  gt  
res:team[.!=$team]/@score])"
                 as="xs:integer"/>
             <td>
                 <xsl:value-of
select="$won"/>
             </td>
             <td>
                 <xsl:value-of
                    
select="count($matches[res:team[.=$team]/@score   
lt res:team[.!=$team]/@score])"/>
             </td>
             <xsl:variable name="drawn"
                
select="count($matches[res:team[.=$team]/@score  eq  
res:team[.!=$team]/@score])"
                 as="xs:integer"/>
             <td>
                 <xsl:value-of
select="$drawn"/>
             </td>
             <td>
                 <xsl:value-of
select="sum($matches/res:team[.=$team]/ 
@score)"/>
             </td>
             <td>
                 <xsl:value-of
select="sum($matches/res:team[.!=$team]/ 
@score)"/>
             </td>
             <td>
                 <xsl:number
value="3*$won+$drawn"/>
             </td>
         </tr>
     </xsl:function>

     <xsl:template match="/">
         <html xsl:validation="strict">
             <!-- xsl:validation="strict"
possible in html tag -->
             <head>
                 <title>Spielresultate</title>
             </head>
             <body>
                 <xsl:apply-templates/>
             </body>
         </html>
     </xsl:template>

     <xsl:template match="res:results">
         <h2>Results</h2>

         <table cellpadding="10">
             <thead>
                 <tr>
                     <td>Team</td>
                     <td>Played</td>
                     <td>Won</td>
                     <td>Lost</td>
                     <td>Drawn</td>
                     <td>For</td>
                     <td>Against</td>
                     <td>Points</td>
                 </tr>
             </thead>

             <xsl:variable name="teamResults"
as="schema- 
element(xhtml:tr)*">
                 <xsl:for-each-group
select="/res:results/res:match"  
group-by="res:team">
                     <xsl:sequence
select="myf:MakeTableRow(current- 
grouping-key(),current-group())"/>
                 </xsl:for-each-group>
             </xsl:variable>
             <xsl:for-each
select="$teamResults">
                 <xsl:sort
select="./xhtml:td[8]"
order="descending"  
data-type="number"/>
                 <xsl:sort
select="./xhtml:td[6]"
order="descending"/>
                 <xsl:sort
select="./xhtml:td[7]"
order="ascending"/>
                 <xsl:copy-of select="."/>
             </xsl:for-each>

         </table>

     </xsl:template>

</xsl:stylesheet>

------------------------------

Date: Tue, 28 Apr 2009 16:33:47 +0100
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
From: David Carlisle <davidc(_at_)nag(_dot_)co(_dot_)uk>
Subject: Re: [xsl] How to cast current-group() ?
Message-Id:
<200904281533(_dot_)n3SFXlrS029185(_at_)edinburgh(_dot_)nag(_dot_)co(_dot_)uk>

as Michael said the problem isn't so much the schema
typing as the fact
that you are passing a string when the function expects an
element.
this fails
 as="schema-element(res:team)"  
but so would
    as="element()"

Your function expects a team element so just give it one
instead of a
string, there will (presumably) necessarily be a team
element child of
the current node in a valid document so

  <xsl:copy-of
select="myfn:MakeTableRow(team,current-group())"/>

should work and be able to cope with any typing of the
first parameter.

David

________________________________________________________________________
The Numerical Algorithms Group Ltd is a company registered
in England
and Wales with company number 1249803. The registered
office is:
Wilkinson House, Jordan Hill Road, Oxford OX2 8DR, United
Kingdom.

This e-mail has been scanned for all viruses by Star. The
service is
powered by MessageLabs. 
________________________________________________________________________

------------------------------

Date: Tue, 28 Apr 2009 18:55:37 +0200
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
From: Studer Leo <leo(_dot_)studer(_at_)me(_dot_)com>
Subject: Re: [xsl] How to cast current-group() ?
Message-id:
<0DAFB6BC-B67E-4160-A896-9EEA5657A620(_at_)me(_dot_)com>

David

thanks for caring!

as Michael said the problem isn't so much the
schema typing as the  
fact
that you are passing a string when the function
expects an element.

Finally I get it. current-grouping-key() is
xs:anyAtomicType and not  
en element...

blessings
Leo

------------------------------

Date: Wed, 29 Apr 2009 00:42:25 +0200
To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
From: <Anders(_dot_)Svensson(_at_)sorman(_dot_)com>
Subject: Placing an element in a very specific position
Message-ID:
<D69E5A9D77766E43ADB213473C2F82BB02AE9AE1(_at_)s507(_dot_)md1(_dot_)com>
Keywords: disclaimer

Hi,=20

I have a problem where I have been asked if I can put an
element in the
top of the third column in a three-column page. My initial
thought is
that this can't be done. I have tried to investigate
absolute-positioning and floats, but cannot find anything
that would
seem to do this. I have no idea how it would be possible to
decide that
it should end up in the top of the third column
specifically. In the
first column would be easy, and if I could put it in the
header that
should be easy too, but unfortunately the header is not an
option due to
the fact that there are space requirements so that each
column needs to
be utilized completely.=20

Is there any way to do this, or do I need to tell my client
that it
can't be done?=20

Any suggestions greatly appreciated!=20

Regards,=20

Anders
###########################################=0A=
=0A=
This message has been scanned by F-Secure Anti-Virus for
Microsoft =
Exchange.=0A=
For more information, connect to http://www.f-secure.com/

------------------------------

Date: Tue, 28 Apr 2009 20:39:59 -0400
To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
From: "G. Ken Holman"
<gkholman(_at_)CraneSoftwrights(_dot_)com>
Subject: Re: [xsl] Placing an element in a very specific
position
Message-Id:
<7(_dot_)0(_dot_)1(_dot_)0(_dot_)2(_dot_)20090428202827(_dot_)02505178(_at_)wheresmymailserver(_dot_)com>

I regret to confirm your suspicions, unless perhaps there
is an out 
that you have not described.

The column geometry in XSL-FO does not allow you to key out
a hole at 
the top of the third column and flow around it.

But, I can give you a fixed size box at the top of what
looks like 
the third column, into which you flow your element.  But
the box 
cannot grow, so I don't know if you can use it.

And you have to use XSL-FO 1.1.

Create three body regions, each with one column (or two
body regions, 
the first with two columns and the second with one column).
 Create a 
flow map such that the region on the right flows after the
other.

Size this right-most body region shorter than the other,
leaving the 
hole at the top.  This gives the appearance of a third
column when, 
technically, it is a different region.

Into this hole you can place an absolutely-positioned block

container.  If this is only on the first page, then your 
absolutely-positioned block container can be flowed at the
start of 
the flow.  If this is on every page then you can flow that 
absolutely-positioned block container in one of the static
content 
areas.  Whether the content in that hole changes or not
might be an 
issue, but you may be able to use markers to make it vary.

I hope this helps!

. . . . . . . . . . . Ken

p.s. if Mats Hultemark is still with Sorman, please pass on
my 
regards (but I know it is a big company and you may not
know him).

At 2009-04-29 00:42 +0200, Anders(_dot_)Svensson(_at_)sorman(_dot_)com
wrote:
Hi,

I have a problem where I have been asked if I can put
an element in the
top of the third column in a three-column page. My
initial thought is
that this can't be done. I have tried to
investigate
absolute-positioning and floats, but cannot find
anything that would
seem to do this. I have no idea how it would be
possible to decide that
it should end up in the top of the third column
specifically. In the
first column would be easy, and if I could put it in
the header that
should be easy too, but unfortunately the header is not
an option due to
the fact that there are space requirements so that each
column needs to
be utilized completely.

Is there any way to do this, or do I need to tell my
client that it
can't be done?

Any suggestions greatly appreciated!

Regards,

Anders

--
XSLT/XSL-FO/XQuery hands-on training - Los Angeles, USA
2009-06-08
Crane Softwrights Ltd.         
http://www.CraneSoftwrights.com/s/
Training tools: Comprehensive interactive XSLT/XPath
1.0/2.0 video
Video lesson:   
http://www.youtube.com/watch?v=PrNjJCh7Ppg&fmt=18
Video overview: 
http://www.youtube.com/watch?v=VTiodiij6gE&fmt=18
G. Ken Holman                
mailto:gkholman(_at_)CraneSoftwrights(_dot_)com
Male Cancer Awareness Nov'07 
http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers: 
http://www.CraneSoftwrights.com/legal

------------------------------

End of xsl-list Digest
***********************************





--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>