Jeni Tennison
> I wish to break the text into paragraphs only when it reaches a
> <BR TYPE="END">.
Basically, this is a grouping problem.
You want to group all the nodes within the TEXT element according to
which BR[@TYPE = 'END'] they come after and place each group within a
P element.
If you apply templates just to the BR[@TYPE = 'END'] elements, then
you can gather the relevant content for the paragraph at that point:
you know that there need to be as many paragraphs as BR[@TYPE = 'END']
elements (of course as long as they're preceded by some content).
So a template that takes a BR[@TYPE = 'END'] element and outputs a
paragraph of the content preceding it would look something like:
<xsl:template match="BR[@TYPE = 'END']">
<!-- locate the preceding BR -->
<xsl:variable name="br-before"
select="preceding-sibling::BR[@TYPE = 'END'][1]" />
<!-- the content are those nodes that come before this one and
after the preceding BR -->
<xsl:variable name="content"
select="preceding-sibling::node()
[not($br-before) or
generate-id(preceding-sibling::BR
[@TYPE = 'END'][1]) =
generate-id($br-before)]" />
<!-- if there are any nodes in that list -->
<xsl:if test="$content">
<!-- output a paragraph -->
<P>
<!-- with a copy of those nodes as the content -->
<xsl:apply-templates select="$content" />
</P>
</xsl:if>
</xsl:template>
To make this work properly, you need to only apply templates to those
BR elements:
<xsl:apply-templates select="BR[@TYPE = 'END']" />
You also need to create a paragraph for any stray text at the end of
the TEXT element that *doesn't* have a BR[@TYPE = 'END'] following it:
<xsl:variable name="end-content"
select="node()[not(self::BR[@TYPE = 'END']) and
not(following-sibling::BR
[@TYPE = 'END'])]" />
<xsl:if test="$end-content">
<P>
<xsl:apply-templates select="$end-content" />
</P>
</xsl:if>
These both need to go within a template that matches the TEXT element: <xsl:template match="TEXT">
<xsl:apply-templates select="BR[@TYPE = 'END']" />
<xsl:variable name="end-content"
select="node()[not(self::BR[@TYPE = 'END']) and
not(following-sibling::BR
[@TYPE = 'END'])]" />
<xsl:if test="$end-content">
<P>
<xsl:copy-of select="$end-content" />
</P>
</xsl:if>
</xsl:template>
Finally, to ignore all that irrelevant whitespace, you need to strip
spaces within the TEXT element: <xsl:strip-space elements="TEXT" /> This does the grouping that you're after. There are other ways of
doing it - in particular you could use Muenchian grouping with keys in
order to achieve the same effect. You can also write a recursive to
template to do collect the relevant nodes for the paragraph content.
|