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

Re: [xsl] grouping xhtml title with first sibling


Subject: Re: [xsl] grouping xhtml title with first sibling
From: Matthieu Ricaud-Dussarget <matthieu.ricaud@xxxxxxxxx>
Date: Tue, 18 Jan 2011 14:46:16 +0100

Hi Michael,

Thank your for your response. I tried to adapt your solution but I don't get it well.

Maybe I didn't understand your algo but this is what I come out :

I supposed nodes param should be node()* typed and the for-each loop should be applied to $nodes, is this correct?
But then I don't understand why using a group-starting-with, then all my level should be one inside the other, which is not really what I want.


My goal is to prevent *orphans* title, that's why I need to group each title with his first-sibling (with conditions as said before).
I do that to simulate the css rule page-break-after:avoid wich doesn't work well with electronic books.


Anyway this is the XSLT :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/1999/xhtml"
xpath-default-namespace="http://www.w3.org/1999/xhtml"
>
<xsl:output method="xml" indent="yes"/>


<!--default copy-->
<xsl:template match="* | @* | processing-instruction() | comment()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>

<!--keep namespace on top element-->
<xsl:template match="html">
<html xmlns="http://www.w3.org/1999/xhtml">
<xsl:apply-templates/>
</html>
</xsl:template>

<xsl:template match="body">
<xsl:copy copy-namespaces="no">
<xsl:copy-of select="@*"/>
<xsl:call-template name="group">
<xsl:with-param name="level" select="1"/>
<xsl:with-param name="nodes" select="*"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>


<xsl:template name="group">
<xsl:param name="nodes" as="node()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:variable name="hN" select="concat('h', $level)"/>
<xsl:for-each-group select="$nodes" group-starting-with="*[local-name() = $hN]">
<xsl:choose>
<xsl:when test="local-name(current-group()[1]) = $hN">
<div class="group">
<xsl:apply-templates select="current-group()[1]"/>
<xsl:call-template name="group">
<xsl:with-param name="nodes" select="current-group() except current-group()[1]"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</div>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()[1]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>


</xsl:stylesheet>

I will trie to add a "group-ending-with" inside the group-starting-with...

Cheers,

Matthieu

Le 18/01/2011 13:36, Michael Kay a icrit :
You don't need dynamic XPath evaluation for this.

The basic structure you want can be achieved with

<xsl:template name="group">
<xsl:param name="nodes" as="node()"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="*" group-starting-with="*[local-name() = concat('h', $level)]">
<div>
<xsl:call-template name="group">
<xsl:with-param name="nodes" select="current-group()"/>
<xsl:with-param name="level" select="$level + 1"/>
</xsl:call-template>
</div>
</xsl:for-each-group>
</xsl:template>


and then start the recursion off with level="1". You'll have to modify this slightly to avoid getting a div element for the elements that precede the first hN element at each level.

Michael Kay
Saxonica


--
Matthieu Ricaud
IGS-CP
Service Livre numirique


Current Thread
Keywords