分割字符串函数导致堆栈溢出

| 我有一个功能,可以将字符串拆分为长度不超过76个字符的行。该函数的输入是二进制数据,并且我猜想由于二进制数据的长度,我经常会遇到“堆栈溢出”错误。有什么方法可以防止这种情况,还是有更好的分割字符串的方法?这需要使用XSL 1.0完成。
<xsl:template name=\"splitBinaryData\">
    <xsl:param name=\"txt\"/>
    <xsl:param name=\"width\"/>
    <xsl:choose>
        <xsl:when test=\"string-length($txt) &gt; 76 \">
            <xsl:value-of select=\"substring($txt, 1, 76)\"/><xsl:text>&#10;</xsl:text>
            <xsl:call-template name=\"splitBinaryData\">
                <xsl:with-param select=\"substring($txt, 77)\" name=\"txt\"/>
                <xsl:with-param select=\"$width\" name=\"width\"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:when test=\"string-length($txt) &lt; 76 or string-length($txt) = 76\">
            <xsl:value-of select=\"$txt\"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>
提前致谢。     
已邀请:
一种可能是将算法转换为尾递归,并希望您的xslt处理器能够识别出该模式并将其变成循环。除了撒克逊人,我找不到其他xslt处理器支持尾部递归的任何信息。转换通过引入包含拆分文本的累加器变量来工作。然后,“ 1”指令将是模板必须执行的最后一个操作,并且可以将其转换为等同于goto的功能,而无需消耗任何堆栈。
<xsl:template name=\"splitBinaryData\">
    <xsl:param name=\"txt\"/>
    <xsl:param name=\"width\"/>
    <xsl:param name=\"accum\"/>
    <xsl:choose>
        <xsl:when test=\"string-length($txt) &gt; 76 \">
            <xsl:call-template name=\"splitBinaryData\">
                <xsl:with-param select=\"substring($txt, 77)\" name=\"txt\"/>
                <xsl:with-param select=\"$width\" name=\"width\"/>
                <xsl:with-param select=\"concat($accum, substring($txt, 1, 76), \'&#10;\')\" name=\"accum\"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:when test=\"string-length($txt) &lt; 76 or string-length($txt) = 76\">
            <xsl:value-of select=\"concat($accum, $txt)\"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>
编辑:另一个选择是应用分治法的算法。这将问题分解为两个大小相等的子问题,然后组合了它们的解决方案。相对于输入大小,所需的堆栈深度大大减少,并且呈对数增长,而不是线性增长。这里的技巧是使第一个子字符串大小为76个字符的倍数,以避免插入其他换行符。
<xsl:template name=\"splitBinaryData\">
    <xsl:param name=\"txt\"/>
    <xsl:param name=\"width\"/>
    <xsl:variable name=\"len\" select=\"string-length($txt)\" />
    <xsl:choose>
        <xsl:when test=\"$len &gt; 76 \">
            <!-- process the text in two parts of about the same size,
                 the length of the first part should be a multiple of
                 the needed width -->
            <xsl:variable name=\"idx\" select=\"ceiling($len div 76 div 2) * 76\" />
            <xsl:call-template name=\"splitBinaryData\">
                <xsl:with-param select=\"substring($txt, 1, $idx)\" name=\"txt\"/>
                <xsl:with-param select=\"$width\" name=\"width\"/>
            </xsl:call-template>
            <xsl:text>&#10;</xsl:text>
            <xsl:call-template name=\"splitBinaryData\">
                <xsl:with-param select=\"substring($txt, $idx+1)\" name=\"txt\"/>
                <xsl:with-param select=\"$width\" name=\"width\"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select=\"$txt\" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
    
使用\“分隔并征服\”模式,例如:
<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
    <xsl:template match=\"/\" name=\"splitBinaryData\">
        <xsl:param name=\"txt\" select=\"string()\"/>
        <xsl:param name=\"width\" select=\"5\"/>
        <xsl:param name=\"length\" select=\"string-length()\"/>
        <xsl:choose>
            <xsl:when test=\"$length > $width\">
                <xsl:variable name=\"split\"
                 select=\"ceiling($length div $width div 2) * $width\"/>
                <xsl:call-template name=\"splitBinaryData\">
                    <xsl:with-param name=\"txt\"
                     select=\"substring($txt, 1, $split)\"/>
                    <xsl:with-param name=\"width\" select=\"$width\"/>
                    <xsl:with-param name=\"length\" select=\"$split\"/>
                </xsl:call-template>
                <xsl:call-template name=\"splitBinaryData\">
                    <xsl:with-param name=\"txt\"
                     select=\"substring($txt, $split + 1)\"/>
                    <xsl:with-param name=\"width\" select=\"$width\"/>
                    <xsl:with-param name=\"length\" select=\"$length - $split\"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select=\"concat($txt, \'&#xA;\')\"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>
注意:MSXSL 4在我的机器上2秒钟内将XHTML格式(1.4 MB)的XSLT 2.0规范拆分了。     

要回复问题请先登录注册