2011-05-21 173 views
5

我正在創建xsl-fo到rtf樣式表。我遇到的一個問題是將xsl-fo文檔中的多個度量單位轉換爲緹(rtf度量單位)。xsl轉換/翻譯模板

一個特定的代碼片caluclates的列的寬度:

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

...問題是的/@column-width的值可以是從1in(1英寸)什麼20px(20個像素),因此,當我做它會失敗的總和。

我需要以某種方式轉換@column-width以緹equivelant: 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 (., '-.ptxcinme', '-.')"/> 
    <xsl:value-of select="$numeric-value * $scaling-factor"/> 

</xsl:template> 
+0

好問題,+1。查看我的答案,獲得完整而簡單的解決方案。 – 2011-05-21 22:11:44

+0

是的,這是一個*完整的解決方案 - 不僅僅是僞代碼。 – 2011-05-22 00:09:15

+0

我的答案只是一個例子,說明如何使用模板規則來使用'xsl:call-template'。你如何使用'translate'也有一點小錯誤。看到我的答案,希望它有幫助。 – 2011-05-22 09:28:10

回答

3

這種轉變

<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的大序列需要更高效的解決方案,那麼FXSL - scanl可以使用模板/函數 - 請參閱我對上一個問題的回答以獲得完整的代碼示例。

+0

@ Flynn1179:我的算術*是*正確的,有時可能看起來很容易可能「容易」變成不正確:) – 2011-05-21 23:02:24

+0

是的,我已經注意到了,並刪除了我的評論;我誤解了問題的重點在於計算列的寬度,認爲它不應該是累積的。 – Flynn1179 2011-05-21 23:29:31

+0

@ Flynn1179:沒問題,交配。我們都是人類,至少有時候應該會犯錯誤:) – 2011-05-22 00:09:56

1

你可以使用這個模板來利用現有的一個你有:

<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)" />;這完全取決於你。

1

你也可以使用模板功能和xsl:call-template。竊取@Dimitre輸入示例(不要恨我:)我向您展示如何使用您的轉換模板規則與xsl:call-template

在變換中,我遍歷每個table-column,從而收集轉換的值。要轉換該值,我只是調用您的原始模板規則(稍微調整)。然後我使用sum來執行這些值的總和。

請注意,如果您沒有將由translate返回的值強制轉換爲數字,則符合XSLT 2.0的處理器將返回運行時錯誤。


XSLT 2.0撒克遜-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> 

這種變換施加在輸入:

<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