Re: [xsl] Center string

Subject: Re: [xsl] Center string
From: Frédéric Schwebel <Fred.Schwebel@xxxxxxxxxxx>
Date: Thu, 11 Jun 2009 15:19:03 +0200
Hi, I already did everything you say :) 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". But I'll change it and do some tries. I'm about to
find a correct solution.

If you're interested, here's my code (sorry it's french. $sautAGenerer
will be translated to &#10; in output, $carcoup are marking chars that
won't be output so removed when calculating lengthes) :
[...]
<xsl:variable name="longueur2" as="xs:integer" select="$longueur - 6" />
<xsl:variable name="nbLignesIdeal" as="xs:integer"
select="xs:integer(ceiling(string-length(translate(.,$carcoup,'')) div
$longueur2))" />
<xsl:variable name="longueurIdeale" as="xs:integer"
select="xs:integer(round(string-length(translate(.,$carcoup,'')) div
$nbLignesIdeal))"/>
<xsl:variable name="titreMisEnPage" as="xs:string"
select="string-join(doc:centreTitre(tokenize(.,'&pt;'),
$longueurIdeale,$longueur2,''),'')" />
[...]
<xsl:variable name="lignesTitre" as="xs:string*"
select="tokenize(translate($titreMisEnPage,' ',''),$sautAGenerer)" />
<xsl:for-each select="$lignesTitre">
    <xsl:value-of select="functx:repeat-string('&pt;',3 +
xs:integer(floor(($longueur2 - string-length(.)) div 2)))" />
    <xsl:value-of select="concat(.,$sautAGenerer)" />
</xsl:for-each>
[...]

<!-- fonction de mise en ligne des titres avant centrage -->
<xsl:function name="doc:centreTitre" as="xs:string*">
  <xsl:param name="mots" as="xs:string*" />
  <xsl:param name="longueurIdeale" as="xs:integer" />
  <xsl:param name="longueurMax" as="xs:integer" />
  <xsl:param name="dejaFait" as="xs:string?" />

  <xsl:variable name="derniereLigne" as="xs:string"
select='functx:substring-after-last($dejaFait,$sautAGenerer)' />
  <xsl:variable name="motCourant" as="xs:string"
select="translate($mots[1],$carcoup,'')" />
  <xsl:variable name="longueurIdealeCourante" as="xs:integer">
    <xsl:choose>
      <xsl:when test="($longueurIdeale +
round(string-length($motCourant) div 2)) &lt; $longueurMax">
        <xsl:value-of select="xs:integer($longueurIdeale +
round(string-length($motCourant) div 2))" />
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$longueurIdeale" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:variable name="motMisEnPage" as="xs:string">
    <xsl:choose>
      <!-- cas 1 : on est en dibut de ligne -->
      <xsl:when test="string-length($derniereLigne)=0">
        <xsl:value-of select="$motCourant" />
      </xsl:when>
      <!-- cas 2 : le mot rentre dans la ligne de (longueur ideale +
moitie longueur mot courant)-->
      <xsl:when
test="string-length(concat($derniereLigne,$espace,$motCourant)) &lt;=
$longueurIdeale">
        <xsl:value-of select="concat($espace,$motCourant)" />
      </xsl:when>
      <!-- cas 3 : faut passer ` la ligne -->
      <xsl:otherwise>
        <xsl:value-of select="concat($sautAGenerer,$motCourant)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:value-of select="functx:trim($motMisEnPage)" />

  <xsl:if test="count($mots) > 1">
    <xsl:value-of select="doc:centreTitre($mots[position() > 1],
$longueurIdeale, $longueurMax,
concat(functx:trim($dejaFait),functx:trim($motMisEnPage)))" />
  </xsl:if>
</xsl:function>

2009/6/11 Michael Kay <mike@xxxxxxxxxxxx>:
>
> I think you need to move from
>
> (0) a set of examples, to
>
> (1) a requirement statement, to
>
> (2) an algorithm, to
>
> (3) an implementation in XSLT code.
>
> Perhaps (1) is something like: generate the output in as few lines as
> possible given the maximum line length, and then divide the words between
> lines so as to minimize the maximum variation between actual line length
and
> average line length.
>
> Perhaps (2) is something like:
>
>  (a) compute the minimum number of lines by first trying to pack the words
> as densely as possible.
>
>  (b) compute the average line length by dividing the total length by the
> minimum number of lines
>
>  (c) flow the words into lines breaking each line at the closest possible
> point to the average line length.
>
> If that's OK, then step (3) is relatively straightforward so long as you
are
> comfortable with recursion, though like most such things it's likely to be
> much easier in XSLT 2.0 than in 1.0.
>
> Regards,
>
> Michael Kay
> http://www.saxonica.com/
> http://twitter.com/michaelhkay

Current Thread