It's certainly a tricky one. I think the key is that instead of the
recursive call passing "substring-after", it has to pass (a) the
substring after the newline in the current text node, plus (b) the
following sibling nodes. This is probably a lot easier in 2.0 where you
can pass a heterogeneous sequence, but I think you can probably do it in
1.0 with two parameters, a string and a node-set. If the string is
empty, you look at the node-set; if the first node is an element, you
copy it out; if the first node is a text node, you look for newlines in
it.
Michael Kay
-----Original Message-----
From: owner-xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
[mailto:owner-xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com] On Behalf Of
Brook Ellingwood
Sent: 26 August 2003 18:19
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: Passing element nodes through string functions (WAS
RE: [xsl]Preserving inline elements when using string functions)
Hi,
I'm pretty close to deciding that what I'm trying to do is
impossible, but before I give I'm going to try rephrasing my
question and see if anyone has any ideas. Apologies for
taking up bandwidth by reposting.
I have elements containing PCDATA in the form of strings plus
child elements, which contain strings and have attributes.
<page>
<bodytext>This is the <link url="">link</link>
This is another line</bodytext>
</page>
I am serially applying two templates to these elements. The
first template transforms the <link> element into an HTML <a
href> element. The second template takes the output from the
first template, identifies the sections of text set apart by
CR/LF and surrounds them with an HTML <div> element. The
problem I am having is that the "substring-before" and
"substring-after" functions in the second template cause the
child elements (the post-transform <a href> tags) to be
discarded. Here is the XSL:
<!-- begin a href transforms -->
<xsl:template name="embeddedLinks">
<xsl:apply-templates select="./node()"/>
</xsl:template>
<xsl:template match="link">
<a style="text-decoration:underline"><xsl:attribute
name="href"><xsl:value-of select="@url"/></xsl:attribute><xsl:value-of
select="."/></a>
</xsl:template>
<!-- begin div transforms -->
<xsl:template name="paragraphs">
<xsl:param name="string" />
<xsl:param name="linebreak" select="'
'" />
<xsl:param name="divClass" />
<xsl:choose>
<xsl:when test="contains($string, $linebreak)">
<DIV><xsl:attribute name="class"><xsl:value-of
select="$divClass" /></xsl:attribute>
<xsl:copy-of
select="substring-before($string, $linebreak)" />
</DIV>
<xsl:call-template name="paragraphs">
<xsl:with-param name="string"
select="substring-after($string, $linebreak)" />
<xsl:with-param name="linebreak"
select="$linebreak" />
<xsl:with-param name="divClass" select="$divClass" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<DIV><xsl:attribute name="class"><xsl:value-of
select="$divClass" /></xsl:attribute>
<xsl:copy-of select="$string" />
</DIV>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- begin template calls and outputting -->
Test 1: Links<br/>
<xsl:for-each select="./page/bodytext">
<xsl:call-template name="embeddedLinks" />
</xsl:for-each>
<br/><br/>Test 2: Paragraphs<br/>
<xsl:for-each select="./page/bodytext">
<xsl:call-template name="paragraphs">
<xsl:with-param name="divClass" select="'para'" />
<xsl:with-param name="string">
<xsl:copy-of select="."/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<br/>Test 3: Links and Paragraphs<br/>
<xsl:for-each select="./page/bodytext">
<xsl:call-template name="paragraphs">
<xsl:with-param name="divClass" select="'para'" />
<xsl:with-param name="string" >
<xsl:call-template name="embeddedLinks" />
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
As you can see, I've got three different output tests to
check each stage of the transform. Here is my output (cleaned
up slightly for readability):
Test 1: Links<br>
This is the <a style="text-decoration:underline" href="">link</a>
This is another line<br>
<br>Test 2: Paragraphs<br>
<DIV class="para">This is the link</DIV>
<DIV class="para"> This is another line</DIV>
<br>Test 3: Links and Paragraphs<br>
<DIV class="para">This is the link</DIV>
<DIV class="para"> This is another line</DIV>
I could get around this by making any elements in the XML
that will have contents like this into CDATA, but to my way
of thinking, that's like putting processing instructions in
the XML. I'd rather keep it pure and do the work on the XSL
side. But, as I said, I'm starting to think this may be
impossible. If anyone thinks differently, I'd love to hear from them.
Thanks,
-- Brook
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list