Andy Fish wrote:
I'm stuck with an XSL problem - can anyone give me any hints?
I have some XML with nested formatting tags like this:
<text>
this is plain
<bold>
this is bold
<italic>
this is bold-italic
</italic>
</bold>
this is plain
</text>
which I need to 'flatten out' into something like this:
<text>this is plain</text>
<text bold="true">thi s is bold</text>
<text bold="true" italic="true">t his is bold-italic</text>
<text>this is plain</text>
It doesn't have to work with any arbitrary tags - there are only a few
possible ones - but I'm not sure how to "remember" the outer level
formatting nodes when processing the text inside. It seems to be
crying out for some kind of state variable
Modes can help to give some kind of state in which a node is to be
processed, here is my attempt at using them to solve the problem:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:styleshe et version="1.0"
xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="text">
<xsl:apply-templates select="node()" mode="flatten" />
</xsl:template>
<xsl:template match="text()" mode="flatten">
<text><xsl:valu e-of select="." /></text>
</xsl:template>
<xsl:template match="bold" mode="flatten">
<xsl:apply-templates select="node()" mode="flattenBo ld" />
</xsl:template>
<xsl:template match="text()" mode="flattenBo ld">
<text bold="true"><xs l:value-of select="." /></text>
</xsl:template>
<xsl:template match="italic" mode="flattenBo ld">
<xsl:apply-templates select="node()" mode="flattenBo ldItalic" />
</xsl:template>
<xsl:template match="text()" mode="flattenBo ldItalic">
<text bold="true" italic="true">< xsl:value-of select="." /></text>
</xsl:template>
</xsl:stylesheet>
The result is not quite what you want but besides a white space text
node showing up it has the right structure (note I wrapped your source
above in a <doc> element as otherwise if the result is flattened it
wouldn't have a root element):
<doc>
<text>
this is plain
</text>
<text bold="true">
this is bold
</text>
<text italic="true" bold="true">
this is bold-italic
</text>
<text bold="true">
</text>
<text>
this is plain
</text>
</doc>
Now to solve the whitespace text node issue I think the following should
help:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:styleshe et version="1.0"
xmlns:xsl="http ://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="text">
<xsl:apply-templates select="node()" mode="flatten" />
</xsl:template>
<xsl:template match="text()" mode="flatten">
<xsl:variable name="normalize dText" select="normali ze-space(.)" />
<xsl:if test="$normaliz edText">
<text><xsl:valu e-of select="." /></text>
</xsl:if>
</xsl:template>
<xsl:template match="bold" mode="flatten">
<xsl:apply-templates select="node()" mode="flattenBo ld" />
</xsl:template>
<xsl:template match="text()" mode="flattenBo ld">
<xsl:variable name="normalize dText" select="normali ze-space(.)" />
<xsl:if test="$normaliz edText">
<text bold="true"><xs l:value-of select="." /></text>
</xsl:if>
</xsl:template>
<xsl:template match="italic" mode="flattenBo ld">
<xsl:apply-templates select="node()" mode="flattenBo ldItalic" />
</xsl:template>
<xsl:template match="text()" mode="flattenBo ldItalic">
<xsl:variable name="normalize dText" select="normali ze-space(.)" />
<xsl:if test="$normaliz edText">
<text bold="true" italic="true">< xsl:value-of select="." /></text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
--
Martin Honnen
http://JavaScript.FAQTs.com/