[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] grouping based on string but with child nodes


Subject: Re: [xsl] grouping based on string but with child nodes
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Mon, 13 Oct 2008 12:47:14 -0400

At 2008-10-13 17:12 +0100, James Cummings wrote:
Just to make sure I'm understanding it, a couple questions
interspersed below with my understanding of what it does.

On Mon, Oct 13, 2008 at 16:40, G. Ken Holman
<gkholman@xxxxxxxxxxxxxxxxxxxx> wrote:
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>                xmlns:dummy="urn:x-Dummy"
>                exclude-result-prefixes="dummy"
>                version="2.0">

Sticking stuff into a dummy namespace, but really I could use the
namespace of the intended output couldn't I?

I suppose, but does the use of that element *really* mean what you say it is? Where I needed a dummy element I explicitly called it a dummy element.


> <xsl:template match="title">
>  <xsl:variable name="separated-titles" as="node()*">
>    <xsl:apply-templates mode="separate-titles"/>
>  </xsl:variable>

Make a variable called separated-titles which uses a mode to apply the
appropriate templates below.  Does one need to cast it as node()*? I
almost never do this, I guess I'm  a bit sloppy with typing of things

It changes how the processor looks at the title elements. Without it, $separated-titles has only a single node, that being the root of the temporary tree. By indicating this type then the processor creates a set of nodes instead of a tree of nodes. The set of nodes is important for the way I've written for-each-group ... if it were a tree I would have had to address the child nodes of the tree root.


>  <xsl:variable name="titles" as="element(title)*">
>    <xsl:for-each-group select="$separated-titles"
>                        group-starting-with="dummy:dummy">
>      <title>
>        <xsl:copy-of select="current-group()[not(self::dummy:dummy)]"/>
>      </title>
>    </xsl:for-each-group>
>  </xsl:variable>
>  <xsl:copy-of select="$titles"/>
> </xsl:template>

Make a variable that does a for-each-group, here cast as
element(title)* which I'm not sure I understand but I'm guessing means
that the output of the variable is required to be zero-or-more title
elements?

Yes, instead of a single node being the top of a temporary tree.


Mike Kay's advice in his posts has convinced me that typing is so very important. In my XSLStyle documentation methodology I enforce a stylesheet writing rule that mandates every global variable be explicitly typed, otherwise the violation is flagged visibly in the documentation.

grouping with groups starting with the dummy:dummy element
maybe before.  And the content is to copy the entire thing but exclude
from that copy the very dummy:dummy that you're grouping by.  nifty!

Yes ... note that the first group doesn't have a dummy:dummy so you cannot use:


current-group()[position()>1]

... which is what I would have used if *every* group began with a dummy:dummy element. But when using group-starting-with= there may be (as here) a set of nodes not meeting the criterion, therefore the first group doesn't in fact start with the element.

> <xsl:template match="*" mode="separate-titles">
>  <xsl:copy-of select="."/>
> </xsl:template>

Copy everything in separate-titles mode.

Copy every *element* ... this handles the <emph> or any other element. Note that this doesn't process the content, it copies the element and its descendants in their entirety. This allows you to have "||" in the emphasized content because it really is content and not a delimiter between titles.


> <xsl:template match="text()" mode="separate-titles">
>  <xsl:analyze-string select="." regex="\|\|">
>    <xsl:matching-substring>
>      <dummy:dummy/>
>    </xsl:matching-substring>
>    <xsl:non-matching-substring>
>      <xsl:value-of select="."/>
>    </xsl:non-matching-substring>
>  </xsl:analyze-string>
> </xsl:template>

For every text node inside a title (since this is
mode="separate-titles") use analyze-string to find every escaped ||,
which is fine because we're just handling the text nodes.

In fact we are only handling the child text nodes of the original <title>, not descendent text nodes.


Cool. I actually think I understand that at the moment.  Must remember
to use analyze-string on text nodes more....

Yes, you've got a handle on it all, and you were heading in the right direction from the start.


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

--
Upcoming XSLT/XSL-FO hands-on courses:      Wellington, NZ 2009-01
Training tools: Comprehensive interactive XSLT/XPath 1.0/2.0 video
Video sample lesson:    http://www.youtube.com/watch?v=PrNjJCh7Ppg
Video course overview:  http://www.youtube.com/watch?v=VTiodiij6gE
G. Ken Holman                 mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/s/
Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal


Current Thread