Re: [xsl] Move elements to preceding parent

Subject: Re: [xsl] Move elements to preceding parent
From: Israel Viente <israel.viente@xxxxxxxxx>
Date: Wed, 17 Jun 2009 23:11:50 +0300
Hi Ken,

I really appreciate your code and comments, but after reading it many
times, I can't reach to the bottom of the logic here.
I'm a newbie so forgive my stupid questions.

1. Why do we need the outer most copy element:
> <xsl:template match="body">
>  <xsl:copy>
How does it work in combination with xsl:for-each-group?

2. Can you please explain the group-ending-with selection?
Why do we need *[not(self::p)] ? Doesn't it mean all except p elements?

Thanks, Viente

On Sun, Jun 14, 2009 at 6:39 PM, G. Ken
Holman<gkholman@xxxxxxxxxxxxxxxxxxxx> wrote:
> At 2009-06-14 17:53 +0300, Israel Viente wrote:
>>
>> I am working with Saxon-B9.1 on the command line (XSLT 1.0 or 2.0 are OK).
>>
>> My input is something like the following:
>> ...
>> The reault output should be:
>
> Thank you for supplying complete examples to make the job of helping
easier.
>
>> For every span element that the class<>'chapter' verify that in every
>> p the last span element text ends with one character of .?"!
>> (paragraph ending char).
>> If it does, copy as is to the output.
>> Otherwise: Move the span elements from the next p to the current one
>> and remove the next p completely.
>>
>> I tried doing it with following-sibling & for-each , but I'm not sure
>> it is the right approach.
>
> That wasn't the approach that came to mind immediately for me.  I've
learned
> over the years that the reach of following-sibling is usually too extensive
> to help out in many algorithms.
>
> With the advent of XSLT 2.0 what comes to mind immediately for me for such
> cases is grouping.  And I think it fits well here, though I am a bit
> concerned your requirement may be under-specified.  Certainly I could
> rewrite your requirement by considering where paragraphs need to be
> considered part of the same group when the span movement you need is being
> triggered.
>
> The code below groups all of the elements of interest such that the group
> always ends in a paragraph with the desired punctuation.  Then I simply
copy
> the first as is and the spans and paragraph white-space of the others.  I
> didn't know what to do with the NBSP characters of the others and you only
> said spans, so I only copied the white-space.  Given this is paragraph
> content between the spans, perhaps all text nodes should be preserved and
> not just indentation.  If so, just take the predicate off of the text()
> address.
>
> I hope this shows how to look at your problem as a grouping problem.
>
> . . . . . . . . . . Ken
>
>
> T:\ftemp>type viente.xml
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE html [<!ENTITY nbsp "&#xa0;">]>
> <html xmlns="http://www.w3.org/1999/xhtml";>
> <body>
>   <p dir="rtl">
>      <span class="chapter">line1</span>
>   </p>
>   <p dir="rtl">&nbsp;&nbsp;<br />
>   <span class="regular">line3.</span>
>   <span class="italic">line4</span>
>   <span class="regular">line5."</span>
>   </p>
>   <p dir="rtl">&nbsp;&nbsp;<br />
>   <span class="regular">line6.</span>
>   <br />
>   <span class="regular">line7</span>
>  </p>
>  <p dir="rtl">&nbsp;&nbsp;<br />
>   <span class="regular">line8.</span>
>   <span class="regular">line9.</span>
>  </p>
> </body>
> </html>
>
> T:\ftemp>call xslt2 viente.xml viente.xsl
> <?xml version="1.0" encoding="UTF-8"?><html
> xmlns="http://www.w3.org/1999/xhtml";>
> <body><p dir="rtl">
>      <span class="chapter">line1</span>
>   </p><p dir="rtl">B B <br />
>   <span class="regular">line3.</span>
>   <span class="italic">line4</span>
>   <span class="regular">line5."</span>
>   </p><p dir="rtl">B B <br />
>   <span class="regular">line6.</span>
>   <br />
>   <span class="regular">line7</span>
>
>   <span class="regular">line8.</span>
>   <span class="regular">line9.</span>
>  </p></body>
> </html>
> T:\ftemp>type viente.xsl
> <?xml version="1.0" encoding="US-ASCII"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>                xpath-default-namespace="http://www.w3.org/1999/xhtml";
>                version="2.0">
>
> <xsl:output indent="no"/>
>
> <xsl:template match="body">
>  <xsl:copy>
>    <xsl:copy-of select="@*"/>
>    <xsl:for-each-group select="*"
>                        group-ending-with="*[not(self::p)] |
>                                           p[span/@class='chapter'] |
>                                           p[matches(span[last()],
>                                                     '[.?&#x22;]$')]">
>      <!--now the information is grouped by p elements that end as
> required-->
>      <xsl:choose>
>        <xsl:when test="current-group()[last()]
>                        [self::p][matches(span[last()],'[.?&#x22;]$')]">
>          <!--in a group of p elements that end as required-->
>          <xsl:copy>
>            <xsl:copy-of select="@*"/>
>            <!--preserve the content of the first of these p elements-->
>            <xsl:apply-templates/>
>            <!--preserve only the span elements and indentation from the
> rest;
>                (the indentation is needed because this is paragraph
>                 white-space)-->
>            <xsl:apply-templates select="current-group()[position()>1]/
>                                         (text()[not(normalize-space())] |
>                                         span)"/>
>          </xsl:copy>
>        </xsl:when>
>        <xsl:otherwise>
>          <!--in another kind of group so just copy these using identity-->
>          <xsl:apply-templates select="current-group()"/>
>        </xsl:otherwise>
>      </xsl:choose>
>    </xsl:for-each-group>
>  </xsl:copy>
> </xsl:template>
>
> <xsl:template match="@*|node()"><!--identity for all other nodes-->
>  <xsl:copy>
>    <xsl:apply-templates select="@*|node()"/>
>  </xsl:copy>
> </xsl:template>
>
> </xsl:stylesheet>
>
> T:\ftemp>rem Done!
>
>
>
> --
> 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@xxxxxxxxxxxxxxxxxxxx
> Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/s/bc
> Legal business disclaimers:  http://www.CraneSoftwrights.com/legal

Current Thread