Xsl convert / translate template

I am creating an xsl-fo stylesheet for rtf. One of the problems I have is converting multiple units of measure in an xsl-fo document to twips (rtf unit).

One particular piece of code displays the width of the columns:

<xsl:value-of select="sum(preceding-sibling:
   :fo:table-column/@column-width) + @column-width"/>

... the problem being the value /@column-widthcan be from 1in(1 inch) to 20px(20 pixels), so when I make the sum, it will not be executed.

I need to somehow convert @column-widthto twip equivelant: 1pt = 19.95 twips, 1px = 15 twips, 1pc = 240 twips, 1in = 1440 twips, 1cm = 567 twips, 1mm = 56.7 twips, 1em = 240 twips

Maybe I can write a method that can perform the conversion, but I am convinced that there is some way to use the function translate()to make it much more efficient.

Please note that my xsl is not so good, so an example of how to achieve this will be appreciated

EDIT

I managed to find something that I want, but have no idea how to call this template from the above calculation:

<xsl:template match="@*" mode="convert-to-twips">
    <xsl:variable name="scaling-factor">
      <xsl:choose>
        <xsl:when test="contains (., 'pt')">19.95</xsl:when>
        <xsl:when test="contains (., 'px')">15</xsl:when>
        <xsl:when test="contains (., 'pc')">240</xsl:when>
        <xsl:when test="contains (., 'in')">1440</xsl:when>
        <xsl:when test="contains (., 'cm')">567</xsl:when>
        <xsl:when test="contains (., 'mm')">56.7</xsl:when>
        <xsl:when test="contains (., 'em')">240</xsl:when>
        <!-- guess: 1em = 12pt -->
        <xsl:otherwise>1</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="numeric-value"
         select="translate (., '-0123456789.ptxcinme', '-0123456789.')"/>
    <xsl:value-of select="$numeric-value * $scaling-factor"/>

 </xsl:template>
+5
source share
3 answers

This conversion is :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 xmlns:fo="some:fo" xmlns:my="my:my" >
 <xsl:output method="text"/>

 <my:units>
  <unit name="pt">19.95</unit>
  <unit name="in">1440</unit>
  <unit name="cm">567</unit>
  <unit name="mm">56.7</unit>
  <unit name="em">240</unit>
  <unit name="px">15</unit>
  <unit name="pc">240</unit>
 </my:units>

 <xsl:variable name="vUnits" select=
      "document('')/*/my:units/*"/>

 <xsl:template match="/">
   <xsl:apply-templates select="*/*/*/@column-width"/>
 </xsl:template>

 <xsl:template match="@column-width">
  <xsl:variable name="vQuantity" select=
      "substring(.,1, string-length() -2)"/>
  <xsl:variable name="vUnit" select=
      "substring(., string-length() -1)"/>

  <xsl:variable name="vrtfAccumWidth">
   <num>0</num>
   <xsl:for-each select=
     "../preceding-sibling::fo:table-column/@column-width">
    <xsl:variable name="vQ" select=
      "substring(.,1, string-length() -2)"/>
    <xsl:variable name="vU" select=
      "substring(., string-length() -1)"/>

     <num>
      <xsl:value-of select=
       "$vQ * $vUnits[@name=$vU]"/>
     </num>
   </xsl:for-each>
  </xsl:variable>

  <xsl:value-of select=
  "$vQuantity * $vUnits[@name=$vUnit]
  +
   sum(ext:node-set($vrtfAccumWidth)/num)
  "/>

  <xsl:text>&#xA;</xsl:text>
 </xsl:template>
</xsl:stylesheet>

when applied to the following XML document (since none of them were provided!):

<fo:fo xmlns:fo="some:fo">
 <fo:table>
  <fo:table-column column-width="2pt"/>
  <fo:table-column column-width="2in"/>
  <fo:table-column column-width="2cm"/>
  <fo:table-column column-width="2mm"/>
  <fo:table-column column-width="2em"/>
  <fo:table-column column-width="2px"/>
  <fo:table-column column-width="2pc"/>
 </fo:table>
</fo:fo>

creates the desired, correct result :

39.9
2919.9
4053.9
4167.3
4647.3
4677.3
5157.3

Note . If a large sequence fo:table-column\@column-widthrequired a more efficient solution, FXSL - pattern / function can be used - see my answer to your previous question for the full sample code.. scanl

+3
source

You can use this template to use your existing one:

<xsl:template match="@column-width">
  <xsl:variable name="previous">
    0<xsl:apply-templates select="../preceding-sibling::*[1]/@column-width" />
  </xsl:variable>
  <xsl:variable name="this">
    <xsl:apply-templates select="." mode="convert-to-twips"/>
  </xsl:variable>
  <xsl:value-of select="$previous + $this" />
</xsl:template>

, , , . , 0 <xsl:apply-templates ; , . , "0" "".

, <xsl:value-of select="$previous + ($numeric-value * $scaling-factor)" /> ; .

+1

xsl:call-template. @Dimitre ( :) , xsl:call-template.

table-column, . , ( ). sum .

, , XSLT 2.0, , , translate, .


XSLT 2.0 is tested in Saxon-B 9.0.0.4J

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="some:fo">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="fo:table/fo:table-column">

        <xsl:variable name="twips">
            <twips>
                <xsl:for-each select="preceding-sibling::fo:table-column/@column-width">
                    <twip>
                        <xsl:call-template name="convert-to-twips">
                            <xsl:with-param name="value" select="."/>
                        </xsl:call-template>
                    </twip>
                </xsl:for-each>
                <twip>
                        <xsl:call-template name="convert-to-twips">
                            <xsl:with-param name="value" select="@column-width"/>
                        </xsl:call-template>
                </twip>
            </twips>
        </xsl:variable>

        <xsl:value-of select="sum($twips//twip)"/><xsl:text> </xsl:text>

    </xsl:template>

    <xsl:template name="convert-to-twips">

        <xsl:param name="value"/>

        <xsl:variable name="scaling-factor">
            <xsl:choose>
                <xsl:when test="contains ($value, 'pt')">19.95</xsl:when>
                <xsl:when test="contains ($value, 'px')">15</xsl:when>
                <xsl:when test="contains ($value, 'pc')">240</xsl:when>
                <xsl:when test="contains ($value, 'in')">1440</xsl:when>
                <xsl:when test="contains ($value, 'cm')">567</xsl:when>
                <xsl:when test="contains ($value, 'mm')">56.7</xsl:when>
                <xsl:when test="contains ($value, 'em')">240</xsl:when>
                <!-- guess: 1em = 12pt -->
                <xsl:otherwise>1</xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

        <xsl:variable name="numeric-value"
            select="number(translate ($value, '-0123456789.ptxcinme', '-0123456789.'))"/>
        <xsl:value-of select="$numeric-value * $scaling-factor"/>

    </xsl:template>

</xsl:stylesheet>

This is a conversion applied to an input:

<fo:fo xmlns:fo="some:fo">
 <fo:table>
  <fo:table-column column-width="2pt"/>
  <fo:table-column column-width="2in"/>
  <fo:table-column column-width="2cm"/>
  <fo:table-column column-width="2mm"/>
  <fo:table-column column-width="2em"/>
  <fo:table-column column-width="2px"/>
  <fo:table-column column-width="2pc"/>
 </fo:table>
</fo:fo>

It produces:

39.9 2919.9 4053.9 4167.3 4647.3 4677.3 5157.3 
+1
source

All Articles