[xsl] Plain text wrapped multiple columns

Subject: [xsl] Plain text wrapped multiple columns
From: Peter Van de Water <peter.vandewater@xxxxxxxxxxxxxxx>
Date: Fri, 10 Jan 2003 12:39:51 +1300
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 &gt;= $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 &gt; $size and $remainder
&gt;= $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>-&#xA;</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 &lt;= $size or $remainder &lt;
$MINIMUM_WIDTH">
			
				<!-- Move to a new column -->
				<xsl:if test="$length &gt; $remainder -
$space">
					<xsl:text>&#xA;</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 &lt;= $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


Current Thread