I need to convert XML into fixed width plain text output in multiple
columns.
<Example>
<Text>Hello World</Text>
<Text>from New Zealand</Text>
</Example>
Page width 16
Hello from New
World Zealand
I have the wrapping sorted but now trying to add multiple columns in is
causing me grief. Any pointers would be much appreciated. The problem I see
coming is $rest will be a result tree fragment and I won't be able to use
position() on to continue the recursion.
Options that come to mind:
* Can it be done with Formatting Objects? I haven't touched this to date
* Start by converting everything to a pipe delimited string and work through
that
* Preform a double pass, output of the first will be xml with each wrapped
line a separate element and second to form the text columns
Thanks for your thoughts, Peter
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="selecticaLib.xsl"/>
<xsl:output method="text"/>
<xsl:param name="width"/>
<xsl:template match="/Example">
<xsl:call-template name="column">
<xsl:with-param name="columns" select="Text"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="column">
<xsl:param name="columns"/>
<xsl:variable name="size" select="$width div
count($columns)"/>
<xsl:call-template name="wrap">
<xsl:with-param name="size" select="$size"/>
<xsl:with-param name="remainder" select="$size"/>
<xsl:with-param name="text" select="$columns[1]"/>
<xsl:with-param name="rest"
select="$columns[position() != 1]"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="wrap">
<xsl:param name="size"/>
<xsl:param name="remainder"/>
<xsl:param name="text"/>
<xsl:param name="rest"/>
<xsl:variable name="MINIMUM_WIDTH" select="3"/> <!-- Needed
so minimum hyphenating doesn't fail -->
<!-- Text remaining to process -->
<xsl:if test="$text and $size >= $MINIMUM_WIDTH">
<xsl:variable name="beforeSpace"
select="substring-before($text, ' ')"/>
<xsl:variable name="word">
<xsl:if test="$beforeSpace">
<xsl:value-of
select="$beforeSpace"/>
</xsl:if>
<xsl:if test="not($beforeSpace)">
<xsl:value-of select="$text"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="length"
select="string-length($word)"/>
<xsl:variable name="space" select="$remainder !=
$size"/>
<!-- Hyphenate words bigger than the column width
-->
<xsl:if test="$length > $size and $remainder
>= $MINIMUM_WIDTH"> <!-- Only if there is enough space to bother starting
-->
<xsl:if test="$space">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="substring($word, 1,
$remainder - 1 - $space)"/>
<xsl:text>-
</xsl:text>
<xsl:call-template name="wrap">
<xsl:with-param name="size"
select="$size"/>
<xsl:with-param name="remainder"
select="$size"/>
<xsl:with-param name="text"
select="substring($text, $remainder - $space)"/>
</xsl:call-template>
</xsl:if>
<!-- Words will fit within the column -->
<xsl:if test="$length <= $size or $remainder <
$MINIMUM_WIDTH">
<!-- Move to a new column -->
<xsl:if test="$length > $remainder -
$space">
<xsl:text>
</xsl:text>
<xsl:call-template name="wrap">
<xsl:with-param name="size"
select="$size"/>
<xsl:with-param
name="remainder" select="$size"/>
<xsl:with-param name="text"
select="$text"/>
<xsl:with-param name="rest"
select="$rest"/>
</xsl:call-template>
</xsl:if>
<!-- Append word to existing line -->
<xsl:if test="$length <= $remainder -
$space">
<xsl:if test="$space">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="$word"/>
<xsl:call-template name="wrap">
<xsl:with-param name="size"
select="$size"/>
<xsl:with-param
name="remainder" select="$remainder - $length"/>
<xsl:with-param name="text"
select="substring($text, $length + 2)"/>
<xsl:with-param name="rest"
select="$rest"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:transform>
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list