RE: [xsl] XSLT2, collection(), and xsl:key

Subject: RE: [xsl] XSLT2, collection(), and xsl:key
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Fri, 1 Feb 2008 17:45:11 -0000
Looks to me something like this:

<xsl:variable name="pop" select="collection('...')//*[@type]"/>

<xsl:for-each-group select="$pop" group-by="node-name(.)">
  <h1><xsl:value-of select="current-grouping-key()"/></h1>
  <table>
    <tr>
      <td>document</td>
      <xsl:variable name="types"
select="distinct-values(current-group()/@type)"/>
      <xsl:for-each select="$types">
        <td><xsl:value-of select="."/></td>
      </xsl:for-each>
    </tr>
    <xsl:for-each-group select="current-group()"
group-by="ancestor::p/@xml:id">
    <tr> 
      <td><xsl:value-of select="current-grouping-key()"/></td>
      <xsl:for-each select="$types">
        <td><xsl:value-of
select="count(current-group()[@type=current()])"/></td>
      </xsl:for-each>
    </tr>
  </table>
</xsl:for-each-group>

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

> -----Original Message-----
> From: James Cummings [mailto:cummings.james@xxxxxxxxx] 
> Sent: 01 February 2008 17:23
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] XSLT2, collection(), and xsl:key
> 
> Hiya,
> 
> I'm using the collection() function and Saxon to produce some 
> statistics about how many of which elements of which type in 
> a particular set of documents.
> 
> Let's say that document one has something like:
> 
> <p xml:id="doc1" type="hypothetical">
> There is some text with <seg type="foo">some foo</seg> and 
> occasionally <seg type="blort">blort</seg> and <other 
> type="wibble">wibble</other></p>
> 
> 
> and document two (and up to some really large number) is like:
> 
> <p xml:id="doc2">
> There is another doc with <seg type="foo">some foo</seg> and 
> occasionally <seg type="notBlort">notBlort</seg> and <other 
> type="fluffy">fluffy other</other> and <some
>   name="thing">someThing</some></p>
> 
> What I want to produce are tables of counts of specific 
> elements, by document and type. So something like the 
> following (though using table/row/cell xml markup):
> 
> 
> table: other
> document | fluffy | wibble | stuff
> doc1 | 0 | 1 | 0
> doc2 | 1 | 0 | 0
> doc3 | 20 | 12 | 54
> 
> table: seg
> document | blort | foo | notBlort
> doc1 | 1 | 1 | 0
> doc2 | 0 | 1| 1
> doc3 | 23 | 44 | 58
> 
> table: some
> document | thing | else | now
> doc1 | 0 | 0 | 0
> doc2 | 1 | 0 | 0
> doc3 | 12 | 5 | 24
> 
> I can build this manually (and for one element I have done 
> so) by doing:
> 
> <xsl:variable name="docs" 
> select="collection('../../working/xml/docs.xml')"/>
> <xsl:template name="main">
> <table><head>seg by type</head>
> <row rend="label">
> <cell>document</cell>
> <cell>blort</cell>
> <cell>foo</cell>
> <cell>notBlort</cell>
> </row>
> <xsl:for-each select="$docs//p"> <!-- let's pretend p is the 
> root element --> <row> <xsl:variable name="doc" 
> select="@xml:id"/> <cell><xsl:value-of select="$doc"/></cell> 
> <cell><xsl:value-of select="count(.//seg[@type='blort'])</cell>
> <cell><xsl:value-of select="count(.//seg[@type='foo'])</cell>
> <cell><xsl:value-of select="count(.//seg[@type='notBlort'])</cell>
> </row>
> </xsl:for-each>
> </table>
> </xsl:template>
> 
> But that isn't really the point now is it?  I tried to use 
> <xsl:key> but I ran into the problem of it not liking the 
> collection() function as part of the match.
> 
> What I want to do is be able to say for-each doc, build me a 
> table of all the (let's pretend unknown) values of this 
> attribute on this element.  So something like:
> 
> <xsl:for-each select="$docs//p">
> <xsl:value-of select="my:function(other/@type, seg/@type, 
> thing/@name, new/@type)"/> </xsl:for-each>
> 
> and without knowing the values of @type in advance it makes a 
> table like above of them (using distinct-values()?) and 
> counting their occurrences.
> 
> This is a case where I know it must be possible, and I could 
> just go and do it manually, (in reality there are about 10 
> elements with a number of attributes, with around 20 values 
> each), but it just seems
> *wrong* to do it that way. ;-)
> 
> Suggestions?
> 
> Thanks,
> 
> -James

Current Thread