Reputation: 101
I would really appreciate a solution for this task that it's getting me crazy.
I have an xml element that has Free text inside, it could has 2 characters or a whole paragraph
<Description>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </Description>
I need a XSL template to produce this output:
11 lines with 80 charcters each.
For example for the above element, the result will be something like this:
I have been trying using a tokenize function, but no success at all. Thanks in advance.
Gerardo
Upvotes: 1
Views: 429
Reputation: 101
Here's the final solution:
...
<xsl:variable name="lineCount" select="11"/>
<xsl:variable name="charPerLine" select="20"/>
...
<ElementX>
<xsl:call-template name="Texts">
<xsl:with-param name="string" select="bi:fillText(../bi:SalesOrder/bi:Notes/bi:Description,$charPerLine*$lineCount)"/>
<xsl:with-param name="Position">1</xsl:with-param>
<xsl:with-param name="charLength" select="$charPerLine"/>
<xsl:with-param name="lineCount" select="$lineCount"/>
</xsl:call-template>
</ElementX>
<!--Template to fill string. ..example 11 lines, 80 characters each.-->
<xsl:template name="Texts">
<xsl:param name="string"/>
<xsl:param name="Position"/>
<xsl:param name="charLength" />
<xsl:param name="lineCount"/>
<xsl:variable name="line" select="substring($string,1,$charLength)"/>
<xsl:variable name="rest" select="substring($string, $charLength+1)"/>
<xsl:if test="$line">
<xsl:value-of select="$line"/>
<xsl:if test="$Position != $lineCount">
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:if>
<xsl:if test="$rest and $Position < $lineCount">
<xsl:call-template name="Texts">
<xsl:with-param name="string" select="$rest"/>
<xsl:with-param name="Position" select="$Position+1"/>
<xsl:with-param name="charLength" select="$charLength"/>
<xsl:with-param name="lineCount" select="$lineCount"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:function name="bi:fillText">
<xsl:param name="value"/>
<xsl:param name="lengthMax"/>
<xsl:variable name="j" select="$lengthMax - string-length($value)"/>
<xsl:value-of select="concat($value,string-join(
(for $i in 1 to $j
return ' '
),
''
) )"/>
</xsl:function>
Upvotes: 0
Reputation: 243479
I. Here is an XSLT 1.0 solution (the XSLT 2.0 solution is much easier):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vLine" select=
"concat('**********',
'**********',
'**********',
'**********',
'**********',
'**********',
'**********',
'**********'
)
"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:variable name="vsplitResult">
<xsl:call-template name="split">
<xsl:with-param name="pText" select="translate(., '
', '')"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="vnumLines" select=
"ceiling(string-length($vsplitResult) div 81)"/>
<xsl:choose>
<xsl:when test="$vnumLines > 11">
<xsl:value-of select="substring($vsplitResult, 1, 81*11 -1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vremLines" select="11 - $vnumLines"/>
<xsl:value-of select="substring($vsplitResult, 1, 81*($vnumLines -1))"/>
<xsl:call-template name="padRight">
<xsl:with-param name="pText" select="substring($vsplitResult,81*($vnumLines -1)+1)"/>
</xsl:call-template>
<xsl:for-each select="(document('')//node())[not(position() > $vremLines)]">
<xsl:value-of select="concat('
', $vLine)"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template name="split">
<xsl:param name="pText" select="."/>
<xsl:param name="pLineLength" select="80"/>
<xsl:if test="$pText">
<xsl:value-of select="substring($pText, 1, $pLineLength)"/>
<xsl:if test="string-length($pText) > $pLineLength">
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:call-template name="split">
<xsl:with-param name="pText" select="substring($pText, $pLineLength+1)"/>
<xsl:with-param name="pLineLength" select="$pLineLength"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="padRight">
<xsl:param name="pText"/>
<xsl:param name="pTotatLength" select="80"/>
<xsl:value-of select=
"concat($pText,
substring($vLine, 1, $pTotatLength - string-length($pText))
)"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<Description>
text text text text text text text text text text text text text
text text text text text text text text text text text text text text text
text text text text </Description>
the wanted, correct result is produced (I am using the *
character in order to see what exactly is generated):
<Description>text text text text text text text text text text text text texttext text text t
ext text text text text text text text text text text texttext text text text **
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************</Description>
II. XSLT 2.0 solution:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pLineLength" select="80" as="xs:integer"/>
<xsl:param name="pTotalLines" select="11" as="xs:integer"/>
<xsl:param name="pPadChar" select="'*'" as="xs:string"/>
<xsl:variable name="vLine" as="xs:string" select=
"string-join(
(for $i in 1 to $pLineLength
return $pPadChar
),
''
)
"/>
<xsl:template match="/*">
<xsl:variable name="vText" select="translate(., '
', '')"/>
<xsl:copy>
<xsl:value-of separator="
" select=
"(for $numlines in string-length($vText) idiv $pLineLength +1,
$line in 1 to $numlines
return
if($line ne $numlines)
then substring($vText,
1 + ($line -1)*$pLineLength,
$pLineLength)
else
for $lastLine in substring($vText,
1 + ($line -1)*$pLineLength,
$pLineLength)
return
concat($lastLine,
substring($vLine,
1,
$pLineLength - string-length($lastLine))
),
(for $numlines in string-length($vText) idiv $pLineLength +1,
$rem in 1 to $pTotalLines - $numlines
return
$vLine)
)
"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the same XML document (above), the same correct result is produced:
<Description>text text text text text text text text text text text text texttext text text t
ext text text text text text text text text text text texttext text text text **
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************</Description>
Upvotes: 1