Xslt 拆分字符串函数导致堆栈溢出
我有一个函数,可以将一个sting拆分为长度不超过76个字符的行。这个函数的输入是二进制数据,我想由于二进制数据的长度,我经常会得到一个“堆栈溢出”错误。有没有办法防止这种情况发生,或者有没有更好的方法来分割字符串?这需要使用XSL 1.0来完成Xslt 拆分字符串函数导致堆栈溢出,xslt,split,xslt-1.0,Xslt,Split,Xslt 1.0,我有一个函数,可以将一个sting拆分为长度不超过76个字符的行。这个函数的输入是二进制数据,我想由于二进制数据的长度,我经常会得到一个“堆栈溢出”错误。有没有办法防止这种情况发生,或者有没有更好的方法来分割字符串?这需要使用XSL 1.0来完成 <xsl:template name="splitBinaryData"> <xsl:param name="txt"/> <xsl:param name="width"/> <xsl:
<xsl:template name="splitBinaryData">
<xsl:param name="txt"/>
<xsl:param name="width"/>
<xsl:choose>
<xsl:when test="string-length($txt) > 76 ">
<xsl:value-of select="substring($txt, 1, 76)"/><xsl:text> </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) < 76 or string-length($txt) = 76">
<xsl:value-of select="$txt"/>
</xsl:when>
</xsl:choose>
</xsl:template>
提前感谢。一种可能是将算法转换为,希望xslt处理器能够识别模式并将其转换为循环。除此之外,我找不到其他xslt处理器支持尾部递归的任何信息。转换通过引入包含拆分文本的累加器变量来工作。然后,
调用模板
指令将是模板必须执行的最后一个操作,并且可以在不消耗任何堆栈的情况下转换为等效的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) > 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), ' ')" name="accum"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="string-length($txt) < 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 > 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> </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, '
')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
注意:在我的机器上,MSXSL 4在2秒钟内将XSLT 2.0规范拆分为1.4 MB。嗯,我说/写得太快了。它似乎适用于某些文件,但并非所有文件。欢迎您提出任何其他建议。谢谢-与上述内容非常相似,但在将来使用时更加灵活。@Jacqueline:不客气。我没有看到@Jörn Horstmann的更新。这有一点改进:它不会重新计算字符串长度。