xsl-list
[Top] [All Lists]

Re: [xsl] Center string

2009-06-11 09:19:37
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 début 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(_at_)saxonica(_dot_)com>:

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

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>