0

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">&lt;xsl:attribute name=&apos;</xsl:variable>
            <xsl:variable name="concat2">&apos;&gt;&lt;xsl:value-of select=&apos;</xsl:variable>
            <xsl:variable name="concat3">&apos; /&gt;&lt;/xsl:attribute&gt;</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.

2 Answers 2

1

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">&lt;xsl:attribute name=&apos;</xsl:variable>
        <xsl:variable name="concat2">&apos;&gt;&lt;xsl:value-of select=&apos;</xsl:variable>
        <xsl:variable name="concat3">&apos; /&gt;&lt;/xsl:attribute&gt;</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.

Sign up to request clarification or add additional context in comments.

1 Comment

works well after changing $styleValue name. Thank you very much.
1

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>

1 Comment

wow I could get some hint for clear XPath expression. Thank you very much michael.hor257k.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.