Mazhar Mohsin
Mazhar Mohsin

Reputation: 185

Convert XML elements to attributes with calculated values

I am trying to divide elements by a number let say 3.33 and then convert those elements to attributes. The elements are converted but without divide operation.

This is the original xml format

<box>
     <h>721</h>
     <w>198</w>
     <xc>499.</xc>
     <yc>8.5450000000000000e+02</yc>
</box>

Current output is

<box h="721" w="198" xc="499." yc="8.5450000000000000e+02"/>

The XSLT code I am using

<xsl:template match="box">
    <xsl:element name="box">
        <xsl:for-each select="*">
            <xsl:attribute name="{name()}" >
                <xsl:value-of select="text()" />
            </xsl:attribute>
        </xsl:for-each>
    </xsl:element>
</xsl:template>

<xsl:template match="box/@*">
    <xsl:variable name="num">
        <xsl:choose>
            <xsl:when test="contains(., 'e+')">
                <xsl:variable name="factor">
                    <xsl:call-template name="power-of-10">
                        <xsl:with-param name="exponent" select="substring-after(., 'e+')"/>
                    </xsl:call-template>
                </xsl:variable>
                <xsl:value-of select="substring-before(., 'e+') * $factor" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="." />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="$num div 3.3" />
    <xsl:if test="position()!=last()">
        <xsl:text>,</xsl:text>
    </xsl:if>
</xsl:template>

<xsl:template name="power-of-10">
    <xsl:param name="exponent"/>
    <xsl:param name="result" select="1"/>
    <xsl:choose>
        <xsl:when test="$exponent">
            <xsl:call-template name="power-of-10">
                <xsl:with-param name="exponent" select="$exponent - 1"/>
                <xsl:with-param name="result" select="$result * 10"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$result"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Upvotes: 3

Views: 684

Answers (1)

kjhughes
kjhughes

Reputation: 111501

Your second template operates over attributes, yet there are no attributes in your input XML. Realize that the templates match against the input XML, not the output XML.

You can change your second template that does the conversion into a callable template which you can call from the first template. Then, along with eliminating the comma code, you'll get XML output that reflects your specified numeric conversion.

Complete XSLT:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="box">
    <xsl:element name="box">
      <xsl:for-each select="*">
        <xsl:attribute name="{name()}" >
          <xsl:call-template name="convert">
            <xsl:with-param name="val" select="."/>
          </xsl:call-template>
        </xsl:attribute>
      </xsl:for-each>
    </xsl:element>
  </xsl:template>

  <xsl:template name="convert">
    <xsl:param name="val"/>
    <xsl:variable name="num">
      <xsl:choose>
        <xsl:when test="contains(., 'e+')">
          <xsl:variable name="factor">
            <xsl:call-template name="power-of-10">
              <xsl:with-param name="exponent"
                              select="substring-after(., 'e+')"/>
            </xsl:call-template>
          </xsl:variable>
          <xsl:value-of select="substring-before(., 'e+') * $factor" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="." />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="$num div 3.3" />
  </xsl:template>

  <xsl:template name="power-of-10">
    <xsl:param name="exponent"/>
    <xsl:param name="result" select="1"/>
    <xsl:choose>
      <xsl:when test="$exponent">
        <xsl:call-template name="power-of-10">
          <xsl:with-param name="exponent" select="$exponent - 1"/>
          <xsl:with-param name="result" select="$result * 10"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$result"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>  

</xsl:stylesheet> 

XML output

<?xml version="1.0" encoding="UTF-8"?>
<box h="218.4848484848485"
     w="60"
     xc="151.21212121212122"
     yc="258.93939393939394"/>

Upvotes: 2

Related Questions