0

I'm using an XSLT sheet to transform an XML file to a fixed with text file.

My "solution" to make the fixed width fields is to pad them out with leading zeros, I've attempting to do this with the following template

<xsl:template name="padout" >
<xsl:param name="str"/>
<xsl:param name="chr"/>
<xsl:param name="len"/>
<xsl:variable name="pad">
  <xsl:for-each select="1 to $len">
    <xsl:value-of select="$chr" />
  </xsl:for-each>
</xsl:variable>
<xsl:value-of select="substring(concat($str,$pad),1,$len)"/>

And calling it as so:

<xsl:call-template name="padout">
  <xsl:with-param name="str" select="ancestor::PMI/Home/Name"/>
  <xsl:with-param name="chr" xml:space="default"/>
  <xsl:with-param name="len" select="30"/>
</xsl:call-template>

But I get an error saying

Expected end of the expression, found 'to '.

I'm assuming it's referring to the "to" in the for-each line.

I'm using this in a .NET 4.5.2 application in VS2015

var transform = new XslCompiledTransform();
transform.Load(path);
using (StringWriter writer = new StringWriter())
{
     transform.Transform(pmi, null, writer);
}

I'm not experienced with XSLT and I'm now getting frustrated as I've being wrestling with this all afternoon and Google isn't my friend on this one!

EDIT: If VS2015 can't handle XSLT 2.0 can anyone suggest a way to do this in 1.0?

MarkBrad
  • 171
  • 2
  • 10
  • Are you sure you are using an XSLT 2.0 processor like Saxon 9, XmlPrime, Exselt or Altova? – Martin Honnen Jun 10 '16 at 14:21
  • I'm using Visual Studio 15 with a project targeting .NET 4.5.2. var transform = new XslCompiledTransform(); transform.Load(path); transform.Transform(pmi, null, writer); – MarkBrad Jun 10 '16 at 14:36
  • That's an XSLT 1.0 processor. To do padding in XSLT 1.0 you need a *recursive* named template - or do simply :http://stackoverflow.com/questions/31805587/pad-value-with-fix-length-xslt/31805975#31805975 – michael.hor257k Jun 10 '16 at 14:41
  • Hi, I've seen your link but some of the text needs to be 255 chars long and simply adding 255 spaces to concat seems a bit backwards, hence why I'm trying to be a bit clever and loop around the number of space I actually need – MarkBrad Jun 10 '16 at 14:57
  • Using C# and .NET you have the option to use Saxon 9, it has a .NET version you can easily add to your project with Nuget. – Martin Honnen Jun 10 '16 at 15:01
  • @MarkBrad Is your question not answered? – michael.hor257k Jun 13 '16 at 22:43

1 Answers1

1

Here's a rewrite of your template as an XSLT 1.0 recursive template:

<xsl:template name="pad" >
    <xsl:param name="string"/>
    <xsl:param name="length"/>
    <xsl:param name="char" select="'0'"/>
    <xsl:choose>
        <xsl:when test="string-length($string) >= $length">
            <xsl:value-of select="substring($string, 1, $length)"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:call-template name="pad">
                <xsl:with-param name="string" select="concat($char, $string)"/>
                <xsl:with-param name="length" select="$length"/>
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Example of call:

<test>
    <xsl:call-template name="pad">
        <xsl:with-param name="string" select="'ABC'"/>
        <xsl:with-param name="length" select="30"/>
    </xsl:call-template>
</test>

Result:

<test>000000000000000000000000000ABC</test>

Note:

This is a very inefficient method. You'd be much better off using a "bank" of zeros as shown here (255 characters is certainly within reason). For very large numbers, you could use binary based recursion.

Community
  • 1
  • 1
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51