Reputation: 89
I'm trying to change a XML document into xsl:fo by using xslt. In some element nodes of the XML there is HTML style attribute like attribute node, and I want to change its value into separated attribute nodes
sample of XML is...
<books>
<book>
<price style="mycolor:red;myvalign:center;">10</price>
</book>
</books>
and I want to change it like this
<books>
<book>
<price mycolor="red" myvalign="center">10</price>
</book>
</books>
I can tokenize the value of 'style' attribute node (got help from stackoverflow here) and rendering it as key-value paired but I don't know how can I set these key-value pair as attribute of node of calling template.
Below is a xslt I tried, but has error. Could you help me please?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="1.0">
<xsl:template match="books">
<xsl:element name="books">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="book">
<xsl:element name="book">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="price">
<xsl:variable name="style" select="./@style" />
<xsl:variable name="result">
<xsl:call-template name="tokenize">
<xsl:with-param name="style" select="$style" />
</xsl:call-template>
</xsl:variable>
<xsl:element name="price">
<xsl:value-of select="$result"/>
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="style" />
<xsl:variable name="styleFrag" select="substring-before($style, ';')" />
<xsl:if test="$styleFrag">
<xsl:variable name="styleKey" select="substring-before($styleFrag, ':')" />
<xsl:variable name="styleVal" select="substring-after($styleFrag, ':')" />
<xsl:variable name="concat1"><xsl:attribute name='</xsl:variable>
<xsl:variable name="concat2">'><xsl:value-of select='</xsl:variable>
<xsl:variable name="concat3">' /></xsl:attribute></xsl:variable>
<xsl:variable name="concatted" select="concat($concat1, $styleKey, $concat2, $styleVal, $concat3)" />
<xsl:value-of select="$concatted" />
<xsl:call-template name="tokenize">
<xsl:with-param name="style" select="substring-after($style,';')" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Thank you.
Upvotes: 0
Views: 902
Reputation: 117073
Couldn't this be simpler?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@style">
<xsl:call-template name="tokenize-style">
<xsl:with-param name="style" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="tokenize-style">
<xsl:param name="style"/>
<xsl:if test="contains($style, ';')">
<xsl:variable name="declaration" select="substring-before($style, ';')" />
<xsl:attribute name="{normalize-space(substring-before($declaration, ':'))}">
<xsl:value-of select="substring-after($declaration, ':')"/>
</xsl:attribute>
<!-- recursive call -->
<xsl:call-template name="tokenize-style">
<xsl:with-param name="style" select="substring-after($style, ';')" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 167696
Change
<xsl:template match="price">
<xsl:variable name="style" select="./@style" />
<xsl:variable name="result">
<xsl:call-template name="tokenize">
<xsl:with-param name="style" select="$style" />
</xsl:call-template>
</xsl:variable>
<xsl:element name="price">
<xsl:value-of select="$result"/>
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="style" />
<xsl:variable name="styleFrag" select="substring-before($style, ';')" />
<xsl:if test="$styleFrag">
<xsl:variable name="styleKey" select="substring-before($styleFrag, ':')" />
<xsl:variable name="styleVal" select="substring-after($styleFrag, ':')" />
<xsl:variable name="concat1"><xsl:attribute name='</xsl:variable>
<xsl:variable name="concat2">'><xsl:value-of select='</xsl:variable>
<xsl:variable name="concat3">' /></xsl:attribute></xsl:variable>
<xsl:variable name="concatted" select="concat($concat1, $styleKey, $concat2, $styleVal, $concat3)" />
<xsl:value-of select="$concatted" />
<xsl:call-template name="tokenize">
<xsl:with-param name="style" select="substring-after($style,';')" />
</xsl:call-template>
</xsl:if>
</xsl:template>
to
<xsl:template match="price">
<xsl:variable name="style" select="./@style" />
<price>
<xsl:call-template name="tokenize">
<xsl:with-param name="style" select="$style" />
</xsl:call-template>
<xsl:value-of select="."/>
</price>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="style" />
<xsl:variable name="styleFrag" select="substring-before($style, ';')" />
<xsl:if test="$styleFrag">
<xsl:variable name="styleKey" select="substring-before($styleFrag, ':')" />
<xsl:variable name="styleVal" select="substring-after($styleFrag, ':')" />
<xsl:attribute name="{normalize-space($styleKey)}">
<xsl:value-of select="$styleValue"/>
</xsl:attribute>
<xsl:call-template name="tokenize">
<xsl:with-param name="style" select="substring-after($style,';')" />
</xsl:call-template>
</xsl:if>
</xsl:template>
Untested, but should show the approach.
Upvotes: 1