Hi David, Wendell and whoever might be curious,
here is a (somewhat late) follow-up to our discussion of dealing with
configurable inline style nesting.
After testing both of your solutions, I discovered that David's does not
do the right thing: the inner-most run style from the hierarchy is not
wrapped around the text, but ends up as a singleton element just before
the run's text. Wendell's solution, however, works perfectly (after
minor typo corrections), so I favour this one. I even managed to dispose
of one template and of explicit style names, so now the stylesheet looks
like this:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="data:,w"
exclude-result-prefixes="w">
<xsl:variable name="styles_tree"
select="document('wp1style.xml')/style_nesting/*"/>
<xsl:template match="w:r">
<xsl:apply-templates select="$styles_tree" mode="style">
<xsl:with-param name="r" select="."/>
<!-- initiates traversal of the style-nesting tree, carrying the
content -->
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="style">
<!-- matches elements inside the style nesting tree -->
<xsl:param name="r"/>
<xsl:variable name="contents">
<!-- consolidates generation of the contents of this node
since it's the same either way -->
<xsl:apply-templates mode="style">
<!-- continue down the style nesting tree -->
<xsl:with-param name="r" select="$r"/>
</xsl:apply-templates>
<xsl:if test="not(*)">
<!-- but if we're at the bottom, write our text -->
<xsl:value-of select="$r/w:t"/>
</xsl:if>
</xsl:variable>
<xsl:choose>
<xsl:when test="$r/w:rPr/*[local-name()=local-name(current())]">
<!-- if parameterized input has our style, we are copied
(note: you might want a more sophisticated way to map them) -->
<xsl:copy>
<xsl:copy-of select="$contents"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<!-- even if not, we want our content -->
<xsl:copy-of select="$contents"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
As I will be generating the stylesheet, I decided to integrate the
description of the style nesting into the stylesheet itself. That is,
the configuration file is now read only at stylesheet creation time, not
at run time. This gives me a generated stylesheet like this one:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="data:,w"
xmlns:lookup="http://www.srz.de/xmlns/yforkl/xslt/lookup"
exclude-result-prefixes="w lookup">
<lookup:style_nesting>
<lookup:b><lookup:i><lookup:u/></lookup:i></lookup:b>
</lookup:style_nesting>
<xsl:template match="w:r">
<xsl:apply-templates
select="document('')/xsl:stylesheet/lookup:style_nesting/*"
mode="style">
<xsl:with-param name="r" select="."/>
<!-- initiates traversal of the style-nesting tree, carrying the
content -->
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="style">
<!-- matches elements inside the style nesting tree -->
<xsl:param name="r"/>
<xsl:variable name="contents">
<!-- consolidates generation of the contents of this node
since it's the same either way -->
<xsl:apply-templates mode="style">
<!-- continue down the style nesting tree -->
<xsl:with-param name="r" select="$r"/>
</xsl:apply-templates>
<xsl:if test="not(*)">
<!-- but if we're at the bottom, write our text -->
<xsl:value-of select="$r/w:t"/>
</xsl:if>
</xsl:variable>
<xsl:choose>
<xsl:when test="$r/w:rPr/*[local-name()=local-name(current())]">
<!-- if parameterized input has our style, we are copied
(note: you might want a more sophisticated way to map
them) -->
<xsl:element name="{local-name()}">
<xsl:copy-of select="$contents"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<!-- even if not, we want our content -->
<xsl:copy-of select="$contents"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Currently, I am thinking about getting even more "static", by replacing
the above generic style parsing approach by individual generated
"classical" templates, each mapping one style and controlling the
subsequently called templates.
So I'd start out with a template for the outermost style:
<xsl:template match="w:r[w:rPr/w:b]">
<xsl:element name="b">
Inside the template, I would like to pass the same run (w:r) to a
template dealing with the next level's style, matched by
"w:r[w:rPr/w:i]", and so on. I wonder how can I "materialize" the style
hierarchy, read from the configuration file, into a series of properly
chained templates.
My ideas: either use one mode per style-specific template, or one single
named template that gets called recursively, with the current style and
the run's text as parameters. Which way would you recommend?
Yves