将xml元素内容拆分为固定行数

时间:2012-08-06 20:25:13

标签: xml templates xslt split xslt-2.0

我真的很感激这个任务的解决方案让我发疯。

我有一个内部有自由文本的xml元素,它可以包含2个字符或整个段落

  

<Description>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </Description>

我需要一个XSL模板来生成此输出:

11行,每行80个字符。

例如对于上面的元素,结果将是这样的:

enter image description here

我一直在尝试使用tokenize函数,但根本没有成功。 提前谢谢。

了Gerardo

2 个答案:

答案 0 :(得分:1)

<强>予。这是一个XSLT 1.0解决方案(XSLT 2.0解决方案更容易):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vLine" select=
"concat('**********',
        '**********',
        '**********',
        '**********',
        '**********',
        '**********',
        '**********',
        '**********'
        )
"/>

 <xsl:template match="/*">
     <xsl:copy>
       <xsl:variable name="vsplitResult">
           <xsl:call-template name="split">
             <xsl:with-param name="pText" select="translate(., '&#xA;', '')"/>
           </xsl:call-template>
       </xsl:variable>

       <xsl:variable name="vnumLines" select=
       "ceiling(string-length($vsplitResult) div 81)"/>

       <xsl:choose>
        <xsl:when test="$vnumLines > 11">
          <xsl:value-of select="substring($vsplitResult, 1, 81*11 -1)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="vremLines" select="11 - $vnumLines"/>

          <xsl:value-of select="substring($vsplitResult, 1, 81*($vnumLines -1))"/>

          <xsl:call-template name="padRight">
           <xsl:with-param name="pText" select="substring($vsplitResult,81*($vnumLines -1)+1)"/>
          </xsl:call-template>

          <xsl:for-each select="(document('')//node())[not(position() > $vremLines)]">
            <xsl:value-of select="concat('&#xA;', $vLine)"/>
          </xsl:for-each>
        </xsl:otherwise>
       </xsl:choose>
     </xsl:copy>
 </xsl:template>

 <xsl:template name="split">
  <xsl:param name="pText" select="."/>
  <xsl:param name="pLineLength" select="80"/>

  <xsl:if test="$pText">
   <xsl:value-of select="substring($pText, 1, $pLineLength)"/>
   <xsl:if test="string-length($pText) > $pLineLength">
    <xsl:text>&#xA;</xsl:text>
   </xsl:if>

   <xsl:call-template name="split">
     <xsl:with-param name="pText" select="substring($pText, $pLineLength+1)"/>
     <xsl:with-param name="pLineLength" select="$pLineLength"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>

 <xsl:template name="padRight">
  <xsl:param name="pText"/>
  <xsl:param name="pTotatLength" select="80"/>

  <xsl:value-of select=
  "concat($pText,
          substring($vLine, 1, $pTotatLength - string-length($pText))
          )"/>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<Description>
text text text text text text text text text text text text text
text text text text text text text text text text text text text text text
text text text text </Description>

生成了想要的正确结果(我使用*字符以查看确切生成的内容)

<Description>text text text text text text text text text text text text texttext text text t
ext text text text text text text text text text text texttext text text text **
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************</Description>

<强> II。 XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pLineLength" select="80" as="xs:integer"/>
 <xsl:param name="pTotalLines" select="11"  as="xs:integer"/>
 <xsl:param name="pPadChar" select="'*'" as="xs:string"/>

 <xsl:variable name="vLine" as="xs:string" select=
      "string-join(
                   (for $i in 1 to $pLineLength
                     return $pPadChar
                    ),
                   ''
                   )
     "/>
  <xsl:template match="/*">
   <xsl:variable name="vText" select="translate(., '&#xA;', '')"/>

   <xsl:copy>
     <xsl:value-of separator="&#xA;" select=
       "(for $numlines in string-length($vText) idiv $pLineLength +1,
             $line in 1 to $numlines
          return
             if($line ne $numlines)
               then substring($vText, 
                              1 + ($line -1)*$pLineLength, 
                              $pLineLength)
               else
                for $lastLine in substring($vText, 
                                           1 + ($line -1)*$pLineLength, 
                                           $pLineLength)
                 return
                   concat($lastLine, 
                          substring($vLine, 
                                    1, 
                                    $pLineLength - string-length($lastLine))
         ),

        (for $numlines in string-length($vText) idiv $pLineLength +1,
             $rem in 1 to $pTotalLines - $numlines
          return
             $vLine)
          )
       "/>
   </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于同一XML文档(上图)时,会产生相同的正确结果

<Description>text text text text text text text text text text text text texttext text text t
ext text text text text text text text text text text texttext text text text **
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************</Description>

答案 1 :(得分:0)

这是最终的解决方案:

    ...
    <xsl:variable name="lineCount" select="11"/>
    <xsl:variable name="charPerLine" select="20"/>
    ...

<ElementX>
                        <xsl:call-template name="Texts">
                                    <xsl:with-param name="string" select="bi:fillText(../bi:SalesOrder/bi:Notes/bi:Description,$charPerLine*$lineCount)"/>
                                    <xsl:with-param name="Position">1</xsl:with-param>
                                    <xsl:with-param name="charLength" select="$charPerLine"/>
                                    <xsl:with-param name="lineCount" select="$lineCount"/>
                            </xsl:call-template>
                        </ElementX>

<!--Template to fill string. ..example 11 lines, 80 characters each.--> 
<xsl:template name="Texts">
    <xsl:param name="string"/>
    <xsl:param name="Position"/>
    <xsl:param  name="charLength" />
    <xsl:param name="lineCount"/>

    <xsl:variable name="line" select="substring($string,1,$charLength)"/>
    <xsl:variable name="rest" select="substring($string, $charLength+1)"/>
    <xsl:if test="$line">
        <xsl:value-of select="$line"/>
        <xsl:if test="$Position != $lineCount"> 
                <xsl:text>&#x0A;</xsl:text> 
        </xsl:if>
    </xsl:if>
    <xsl:if test="$rest and $Position &lt; $lineCount">
        <xsl:call-template name="Texts">
            <xsl:with-param name="string" select="$rest"/>
            <xsl:with-param name="Position" select="$Position+1"/>
            <xsl:with-param name="charLength"  select="$charLength"/>
            <xsl:with-param name="lineCount" select="$lineCount"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:function name="bi:fillText">
    <xsl:param name="value"/>
    <xsl:param name="lengthMax"/>
    <xsl:variable name="j" select="$lengthMax - string-length($value)"/>

    <xsl:value-of select="concat($value,string-join(
               (for $i in 1 to $j
                 return ' '
                ),
               ''
               ) )"/>
</xsl:function>