2011-05-21 17 views
5

Estoy creando una hoja de estilo xsl-fo a rtf. Uno de los problemas que tengo es convertir las numerosas unidades de medida en un documento xsl-fo en twips (unidad de medida rtf).xsl convertir/traducir plantilla

Una pieza particular de código caluclates las anchuras de las columnas:

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

... problema que el valor de /@column-width podría ser cualquier cosa de 1in (1 pulgada) a 20px (20 píxeles), así que cuando Hago la suma que fallará.

Necesito convertir de alguna manera @column-width a un equivelant twip: 1pt = 19.95 twips, 1px = 15 twips, 1pc = 240 twips, 1in = 1440 twips, 1cm = 567 twips, 1mm = 56.7 twips, 1em = 240 twips

Es probable que pueda escribir un método que puede hacer la conversión, pero estoy convencido de que hay alguna manera de hacer uso de la función translate() hacer esto mucho más eficientemente.

Por favor, tome en cuenta que mi XSL no es tan grande, por lo que un ejemplo de cómo lograr esto será apreciado

EDITAR

he conseguido encontrar algo que quiero, pero no tienen idea cómo llamar a esta plantilla del cálculo anterior:

<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 (., '-.ptxcinme', '-.')"/> 
    <xsl:value-of select="$numeric-value * $scaling-factor"/> 

</xsl:template> 
+0

Buena pregunta, +1. Vea mi respuesta para una solución completa y fácil. –

+0

Sí, y esta es una solución * completa *, no solo un pseudocódigo. –

+0

Mi respuesta quiere ser solo un ejemplo de cómo puede usar su regla de plantilla usando 'xsl: call-template'. También hay un pequeño error en la forma en que está usando 'translate'. Ver mi respuesta, espero que ayude. –

Respuesta

3

esta transformación:

<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> 

cuando se aplica en el siguiente documento XML (como se proporcionó ninguna!):

<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> 

produce el, resultado correcto deseada:

39.9 
2919.9 
4053.9 
4167.3 
4647.3 
4677.3 
5157.3 

Aviso: Si se necesita una solución más eficiente para una gran secuencia de fo:table-column\@column-width, entonces el FXSL - scanl plantilla/función se puede utilizar - consulte mi respuesta a su pregunta anterior para obtener un ejemplo de código completo.

+0

@ Flynn1179: mi aritmética * es * correcta y, a veces, lo que parece fácil podría ser "fácilmente" incorrecto :) –

+0

Sí, ya lo había notado y borré mi comentario; Leí mal la pregunta donde decía que el punto era calcular el ancho de las columnas, pensando que no se suponía que fuera acumulativo. – Flynn1179

+0

@ Flynn1179: No hay problema, amigo. Todos somos seres humanos y se supone que debemos equivocarnos al menos algunas veces :) –

1

Se puede utilizar esta plantilla para hacer uso de la existente tiene:

<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> 

Es bastante sencillo como se puede ver, sólo tiene que calcular el ancho de las columnas anteriores, a continuación, agregarlo a la actual. Probablemente notará que hay un 0 en frente de la instrucción <xsl:apply-templates en la primera variable; eso es para asegurarse de que se le da un número válido a la variable. Si no hay columnas anteriores, almacenará '0' en lugar de ''.

Estrictamente hablando, podría incluir el cuerpo de su plantilla existente en lugar de la segunda variable, y tener <xsl:value-of select="$previous + ($numeric-value * $scaling-factor)" /> en la parte inferior; eso depende de ti.

1

También puede ir con una función de plantilla y xsl:call-template. Robo del ejemplo de entrada de @Dimitre (no me odio :) Te muestro cómo puedes usar tu regla de plantilla de conversión con xsl:call-template.

En la transformación, repito iterativamente en cada table-column reuniendo así los valores convertidos. Para convertir el valor, solo estoy llamando a la regla de plantilla original (un poco sintonizada). Luego uso sum para realizar la suma de los valores.

Tenga en cuenta que un procesador compatible con XSLT 2.0 devolverá un error de tiempo de ejecución si no convierte el valor devuelto por translate en un número.


XSLT 2.0 probado bajo 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, '-.ptxcinme', '-.'))"/> 
     <xsl:value-of select="$numeric-value * $scaling-factor"/> 

    </xsl:template> 

</xsl:stylesheet> 

esta transformación aplicada en la entrada:

<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> 

Produce:

39.9 2919.9 4053.9 4167.3 4647.3 4677.3 5157.3