RE: [xsl] Center string

Subject: RE: [xsl] Center string
From: Emmanuel Bégué <eb@xxxxxxxxxx>
Date: Fri, 12 Jun 2009 01:57:04 +0200
> -----Original Message-----
> On Behalf Of Fridiric Schwebel
>
> Problem is with step 2c "flow the words into lines breaking each
> line AT THE CLOSEST possible point to the average line length."
> The closest is quite hard to know.
>
> I just said "if the current line length + 1 (space) + current
> word length <= average line length, put the word in the same
> line, otherwise put it on a new line".


Hello,

Dealing with a minimum / maximum line length can be done with
regexp: they help produce, I think, more legible stylesheets
-- although it may be a question of taste. See for example this
stylesheet:


<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:p="some namespace">

<xsl:output method="text" indent="no" encoding="ISO-8859-1"/>
<xsl:param name="line-length" select="30"/>

<xsl:template match="/root">
  <xsl:for-each select="text">
    <xsl:call-template name="cut"/>
    </xsl:for-each>
  </xsl:template>

<xsl:template name="cut">
  <xsl:variable name="length" select="if
    (not(contains(substring(.,1,$line-length),' ')))
      then string-length(substring-before(.,' '))
      else $line-length"/>
  <xsl:analyze-string select="." regex="^.{{0,{$length}}}(\s|.$)">
    <xsl:matching-substring>
      <xsl:value-of select="p:center(.)"/>
      </xsl:matching-substring>
    <xsl:non-matching-substring>
      <xsl:choose>
        <xsl:when test="contains(.,' ')">
          <xsl:call-template name="cut"/>
          </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="p:center(.)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:non-matching-substring>
    </xsl:analyze-string>
  </xsl:template>

<xsl:function name="p:center">
  <xsl:param name="line"/>
  <xsl:for-each select="1 to ($line-length - string-length($line)) idiv 2">
    <xsl:value-of select="' '"/>
    </xsl:for-each>
  <xsl:value-of select="concat($line,'&#13;&#10;')"/>
  </xsl:function>

</xsl:stylesheet>


The 'cut' template uses the regexp   ^.{0,30}(\s|.$)
which matches up to 30 characters from the start of the
string, up to either a space or the end of the string.

(The "length" parameter deals with words that are longer
than the line-length, which would otherwise trigger an
infinite loop, by adjusting the line-length (30) to the
length of the word).


Given this source file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
 <text>abcde abcde abcde abcde abcde abcde abcde abcde abcde abcde abcde abcde
abcde abcde abcde abcde abcde</text>
 <text>abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd abcd abcd abcd  abcd abcd abcd abcd abcd abcd abcd
abcd abcd abcd abcd</text>
 <text>Just curious if it has already been done : I need to center a string
with a max line length. The words must be uncut and balanced between
lines.</text>
 <text>Centering the   lines is not a problem. The most difficult part is to
balance words with line-length. Did somebody already do this with XSL
?</text>
 <text>Also deals with words longer than the accepted line-length such as
anticonstitutionnellementmentment and some more text after that
tagada.</text>
 <text>(mathimatiques niveau lycie: sirie '1</text>
 </root>


it gives this result:

abcde abcde abcde abcde abcde
abcde abcde abcde abcde abcde
abcde abcde abcde abcde abcde
         abcde abcde
abcd abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd abcd
abcd abcd abcd abcd abcd abcd
abcd abcd abcd abcd  abcd abcd
abcd abcd abcd abcd abcd abcd
        abcd abcd abcd
Just curious if it has already
been done : I need to center a
string with a max line length.
 The words must be uncut and
   balanced between lines.
Centering the   lines is not a
 problem. The most difficult
part is to balance words with
  line-length. Did somebody
  already do this with XSL ?
Also deals with words longer
than the accepted line-length
           such as
anticonstitutionnellementmentment
and some more text after that
           tagada.
(mathimatiques niveau lycie:
           sirie '1


(Note that it does not normalize the input
strings -- which may or may not be desired).

In your first message you seemed to imply that
you wanted "sirie" and "'1" kept together in all
cases: this calls for the replacement of any
space between those words with an unbreakable
space (which is of course easier if there is
a recognizable pattern, but it seems to be the
case?)

HTH

Regards,
EB

Current Thread