[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]
Subject: Printing formatted text with XSLT (solution)
It seems that printing well formatted text with XSL is a perennial problem. So for the record, here is a solution Ive been using to print docbooks (but should work for just about anything). This stylesheet does left margin padding, width limitation, and stops strings from breaking in midline due to existing newlines. See comments for more info. ----- BEGIN text_format.xsl ----- <?xml version="1.0"?> <!DOCTYPE stylesheet [ <!ENTITY space " "> <!ENTITY cr " "> <!ENTITY tab "	"> <!ENTITY newln " "> ]> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <!-- Breaks string on whitespace. If there is no white space to break on, like in the case of a very long url, the word is wrapped. USAGE Main entry point is template 'format'. Format requires 3 parameters txt : text to format space-padding : spaces to insert as left margin padding width : maximum width of text, including left margin padding For a simple demonstration, call `xsltproc text_format.xsl source.xml | more` to print out all source.xml text in a narrow column. For practical usage, include this file in your stylesheet with <xsl:include href="text_format.xsl"/> and call the format template with something like <xsl:template match="p"> <xsl:call-template name="format"> <xsl:with-param name="txt" source="normalize-space(.)"> <xsl:with-param name="width" select="50"/> <xsl:with-param name="space-padding">20</xsl:with-param> </xsl:call-template> <xsl:text>&newln;</xsl:text> </xsl:template> HISTORY Origional source from http://www.dpawson.co.uk/xsl/sect2/N7240.html#d9312e307 dyssident modified 2006/02/03 use translate() to avoid breaking before intended end of line take space-padding into account when applying width limit added simple test added documentation --> <!-- Testing code Formats all text in source file if this stylesheet is used directly --> <xsl:template match="text()"> <xsl:call-template name="format"> <xsl:with-param name="txt" select="normalize-space(.)"/> <xsl:with-param name="width" select="50"/> <xsl:with-param name="space-padding">10</xsl:with-param> </xsl:call-template> <xsl:text>&newln;</xsl:text> </xsl:template> <!-- This template is the main entry point for text formatting txt: text to process width: maximum text width space-padding: number of padding spaces in left margin --> <xsl:template name="format"> <xsl:param name="txt" /> <xsl:param name="width" /> <xsl:param name="space-padding" /> <!-- get left margin padding --> <xsl:param name="space-pad"> <xsl:call-template name="repeat-chars"> <xsl:with-param name="rep-chars"> <xsl:text>&space;</xsl:text> </xsl:with-param> <xsl:with-param name="times" select="$space-padding"/> <xsl:with-param name="str"></xsl:with-param> </xsl:call-template> </xsl:param> <xsl:if test="$txt"> <!-- real-width determines how man chars our line will contain --> <xsl:variable name="real-width"> <xsl:call-template name="tune-width"> <xsl:with-param name="txt" select="$txt" /> <xsl:with-param name="width" select="$width" /> <xsl:with-param name="def" select="$width" /> <xsl:with-param name="space-padding" select="$space-padding" /> </xsl:call-template> </xsl:variable> <!-- BEGIN output --> <!-- left margin padding --> <xsl:value-of select="$space-pad" /> <!-- translate() is used to remove newlines within the string we will output --> <xsl:value-of select="translate(substring($txt, 1, $real-width), '&newln;', '')" /> <xsl:text>&newln;</xsl:text> <!-- END output --> <!-- iterate with rest of string --> <xsl:call-template name="format"> <xsl:with-param name="txt" select="substring($txt,$real-width + 1)" /> <xsl:with-param name="width" select="$width" /> <xsl:with-param name="space-padding" select="$space-padding" /> </xsl:call-template> </xsl:if> </xsl:template> <!-- Determines position at which string will break --> <xsl:template name="tune-width"> <xsl:param name="txt" /> <xsl:param name="width" /> <xsl:param name="def" /> <xsl:param name="space-padding" /> <!-- real-width decides width of string to output taking into account space-padding --> <xsl:param name="real-width" select="$width - $space-padding"/> <!-- Find point at which string should break--> <xsl:choose> <!-- Just return default width if constraint is zero or string width is less than constraint --> <xsl:when test="$real-width = 0 or string-length($txt)<$real-width"> <xsl:value-of select="$def" /> </xsl:when> <xsl:otherwise> <xsl:choose> <!-- Look for whitespace to break on --> <xsl:when test="substring($txt, $real-width, 1 ) = ' '"> <xsl:value-of select="$real-width" /> </xsl:when> <xsl:otherwise> <!-- Decrement width and iterate tune-width looking for whitespace --> <xsl:call-template name="tune-width"> <xsl:with-param select="$txt" name="txt" /> <xsl:with-param select="$width - 1" name="width" /> <xsl:with-param select="$def" name="def" /> <xsl:with-param name="space-padding" select="$space-padding" /> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- Repeats 'repeat-chars' 'times' times. Used in margin spacing. --> <xsl:template name="repeat-chars"> <xsl:param name="rep-chars"/> <xsl:param name="times"/> <xsl:param name="str"/> <xsl:choose> <xsl:when test="$times > 0"> <xsl:call-template name="repeat-chars"> <xsl:with-param name="rep-chars" select="$rep-chars"/> <xsl:with-param name="times" select="$times - 1"/> <xsl:with-param name="str" select="concat($str, $rep-chars)"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$str"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> ----- END text_format.xsl -----
[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]