xsl конвертировать / переводить шаблон - PullRequest
5 голосов
/ 21 мая 2011

Я создаю таблицу стилей xsl-fo to rtf.Одна из проблем, с которыми я сталкиваюсь, заключается в преобразовании многочисленных единиц измерения в документе xsl-fo в твипы (единицы измерения rtf).

Один конкретный фрагмент кода вычисляет ширину столбцов:

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

... проблема в том, что значение /@column-width может быть любым от 1in (1 дюйм) до 20px (20 пикселей), поэтому, когда я сделаю сумму, она не будет выполнена.

Мне нужно каким-то образом преобразовать @column-width в твипный эквивлант: 1pt = 19.95 twips, 1px = 15 twips, 1pc = 240 twips, 1in = 1440 twips, 1cm = 567 twips, 1mm = 56.7 twips, 1em = 240 twips

Я, вероятно, могу написать метод, который может выполнить преобразование, но я убежден, что есть какой-то способ использоватьtranslate() функция, чтобы сделать это намного эффективнее.

Пожалуйста, обратите внимание, что мой xsl не так уж велик, поэтому пример того, как этого добиться, будет оценен

РЕДАКТИРОВАТЬ

Мне удалось найти то, что я хочу, но не знаю, как вызвать этот шаблон из приведенного выше расчета:

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

Ответы [ 3 ]

3 голосов
/ 22 мая 2011

Это преобразование :

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

при применении к следующему документу XML (так как не было предоставлено ни одного!):

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

дает требуемый, правильный результат :

39.9
2919.9
4053.9
4167.3
4647.3
4677.3
5157.3

Примечание : если для большой последовательности fo:table-column\@column-width требуется более эффективное решение, то *Шаблон / функция 1019 * FXSL - scanl. Полный пример кода см. В моем ответе на предыдущий вопрос.

1 голос
/ 22 мая 2011

Вы также можете пойти с функцией шаблона и xsl:call-template. Пример кражи @Dimitre (не ненавидите меня :) Я покажу вам, как вы можете использовать правило шаблона конвертации с xsl:call-template.

В преобразовании я повторяю каждый table-column, собирая таким образом преобразованные значения. Чтобы преобразовать значение, я просто вызываю ваше оригинальное шаблонное правило (немного настроенное). Затем я использую sum, чтобы выполнить сумму значений.

Обратите внимание, что XSLT 2.0-совместимый процессор вернет ошибку времени выполнения, если вы не приведете значение, возвращаемое translate к числу.


XSLT 2.0 протестировано под 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>

Это преобразование применяется к входу:

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

Производит:

39.9 2919.9 4053.9 4167.3 4647.3 4677.3 5157.3 
1 голос
/ 22 мая 2011

Вы можете использовать этот шаблон, чтобы использовать имеющийся у вас:

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

Это довольно просто, как вы можете видеть, просто рассчитав ширину предыдущих столбцов, а затем добавив ее к текущему. Вы, вероятно, заметите, что перед инструкцией <xsl:apply-templates в первой переменной стоит 0; чтобы убедиться, что переменной присвоено правильное число. Если предыдущих столбцов нет, он будет хранить «0» вместо «».

Строго говоря, вы можете включить тело существующего шаблона вместо второй переменной и иметь <xsl:value-of select="$previous + ($numeric-value * $scaling-factor)" /> внизу; это полностью зависит от вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...