This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: RE: How to transform <BR> to </P><P>
- To: "Sun, Christine (Cahners)" <csun at cahners dot com>
- Subject: Re: [xsl] RE: How to transform <BR> to </P><P>
- From: Jeni Tennison <mail at jenitennison dot com>
- Date: Fri, 19 Jan 2001 15:49:40 +0000
- CC: "'xsl-list at lists dot mulberrytech dot com'" <xsl-list at lists dot mulberrytech dot com>
- Organization: Jeni Tennison Consulting Ltd
- References: <4AF56C92A6C8D211B5F300805F6FFFDB103FF043@binbosexc001>
- Reply-To: xsl-list at lists dot mulberrytech dot com
Hi Chris,
> There are more than <BR> and text() as children of <TEXT>. And I
> wish to break the text into paragraphs only when it reaches a <BR
> TYPE="END">.
I'm not sure what the best way of doing this is, but this is the
method that I usually use. 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.
I haven't addressed outputting the character entity - I think you know
how to do that from last time - or turning the AUTOITALIC element into
an ITALIC element, which you should be able to do yourself, I think?
I hope that helps anyway,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list