Reputation: 107
I have a need to convert all Float and Double data types as defined by a source schema to decimal data types.
We have an existing XSLT that takes an XML document from a third party and transforms it to a XML structure that we can then pass into our 4GL DB appliction. The nice thing about the native 4GL interface is that it can convert an inbound XML into a native Dataset structure. The short fall is that it maps Float and Double data types to character data types.
Is there a way within an XSLT to identify an element that is a Float/Double data type and convert it to a decimal. I was thinking this could be a pre main XSLT step and then pass the output onto the main XSLT.
Sample Schema In:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ttPTManifest">
<xs:complexType>
<xs:sequence>
<xs:element ref="JobCode"/>
<xs:element ref="EstimateHours"/>
<xs:element ref="ActualHours"/>
<xs:element ref="Density"/>
<xs:element ref="NettLitres"/>
<xs:element ref="QuitOutLitres"/>
<xs:element ref="QuitInLitres"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="QuitOutLitres" type="xs:double"/>
<xs:element name="QuitInLitres" type="xs:float"/>
<xs:element name="PTManifestSonicIn">
<xs:complexType>
<xs:sequence>
<xs:element ref="ttPTManifest"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="JobCode" type="xs:string"/>
<xs:element name="NettLitres" type="xs:double"/>
<xs:element name="EstimateHours" type="xs:float"/>
<xs:element name="Density" type="xs:decimal"/>
<xs:element name="ActualHours" type="xs:float"/>
</xs:schema>
Sample XML Data In:
<?xml version="1.0"?>
<PTManifestSonicIn xsi:noNamespaceSchemaLocation="SampleIn.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ttPTManifest>
<JobCode>000123</JobCode>
<EstimateHours>3.14159E3</EstimateHours>
<ActualHours>3.14159E3</ActualHours>
<Density>123.456</Density>
<NettLitres>3.14159265358979E3</NettLitres>
<QuitOutLitres>3.14159265358979E3</QuitOutLitres>
<QuitInLitres>3.14159E3</QuitInLitres>
</ttPTManifest>
</PTManifestSonicIn>
Rerquired Schema Out:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ttPTManifest">
<xs:complexType>
<xs:sequence>
<xs:element ref="JobCode"/>
<xs:element ref="EstimateHours"/>
<xs:element ref="ActualHours"/>
<xs:element ref="Density"/>
<xs:element ref="NettLitres"/>
<xs:element ref="QuitOutLitres"/>
<xs:element ref="QuitInLitres"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="QuitOutLitres" type="xs:decimal"/>
<xs:element name="QuitInLitres" type="xs:decimal"/>
<xs:element name="PTManifestSonicIn">
<xs:complexType>
<xs:sequence>
<xs:element ref="ttPTManifest"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="JobCode" type="xs:string"/>
<xs:element name="NettLitres" type="xs:decimal"/>
<xs:element name="EstimateHours" type="xs:decimal"/>
<xs:element name="Density" type="xs:decimal"/>
<xs:element name="ActualHours" type="xs:decimal"/>
</xs:schema>
Required XML Data Out:
<?xml version="1.0"?>
<PTManifestSonicIn xsi:noNamespaceSchemaLocation="SampleOut.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ttPTManifest>
<JobCode>000123</JobCode>
<EstimateHours>3141.59</EstimateHours>
<ActualHours>3141.59</ActualHours>
<Density>123.456</Density>
<NettLitres>3141.59265358979</NettLitres>
<QuitOutLitres>3141.59265358979</QuitOutLitres>
<QuitInLitres>3141.59</QuitInLitres>
</ttPTManifest>
</PTManifestSonicIn>
Upvotes: 2
Views: 7158
Reputation: 51
If you can use XSL v2, use Mads' answer. If you're stuck with v1, This can do the XSD transformation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xs:element[@type='xs:double' or @type='xs:float']">
<xsl:copy>
<xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="type">xs:decimal</xsl:attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And this could be used to transform the XML:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="*
[local-name(.)=document(/*/@xsi:noNamespaceSchemaLocation)/*/xs:element[@type='xs:double' or @type='xs:float']/@name]
[number(.)=number(.)]">
<xsl:copy>
<xsl:value-of select="number(.)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 66781
In order to transform the XML data, you could use the following stylesheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="*
[local-name(.)=document(/*/@xsi:noNamespaceSchemaLocation)/*/xs:element[@type=('xs:double', 'xs:float')]/@name]
[. castable as xs:double or . castable as xs:float]">
<xsl:copy>
<xsl:value-of select="number(.)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You could transform the Schema with the following stylesheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@type[.=('xs:double', 'xs:float')]">
<xsl:attribute name="type" select="'xs:decimal'"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1