以下脚本说明了 Chrome 42.0.2311.135 在尝试将递归模板escapeStringForJson
应用于长度超过一定长度的字符串(1874个字符)时的静默失败。我把它作为一个bug提交了,但是有没有办法重写模板以便它不是递归的?
var transformXml = function (xml, xslt) {
var xmlScrapeResult = (new DOMParser()).parseFromString(xml, 'text/xml');
var transform = (new DOMParser()).parseFromString(xslt, 'text/xml');
var xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(transform);
var transformed = xsltProcessor.transformToFragment(xmlScrapeResult, document);
if (transformed != null) {
return transformed;
}
else {
throw 'xsltProcessor.transformToFragment() unexpectedly returned null';
}
}
var xslt = '<?xml version="1.0"?>\
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">\
<xsl:preserve-space elements="*" />\
<xsl:template match="/MyRoot">\
{\n\
"escapedDoubleQuotesAndNewlines": "<xsl:call-template name="escapeStringForJson"><xsl:with-param name="text" select="MyElement"/></xsl:call-template>"\n\
}\
</xsl:template>\
<xsl:template name="escapeStringForJson">\
<xsl:param name="text"/>\
<xsl:if test="$text != \'\'">\
<xsl:variable name="head" select="substring($text, 1, 1)"/>\
<xsl:variable name="tail" select="substring($text, 2)"/>\
<xsl:variable name="apos">\'</xsl:variable>\
<xsl:variable name="quot">"</xsl:variable>\
<xsl:variable name="nl"><xsl:text> </xsl:text></xsl:variable>\
<xsl:variable name="cr"><xsl:text> </xsl:text></xsl:variable>\
<xsl:variable name="sl">\</xsl:variable>\
<xsl:choose>\
<!--<xsl:when test="$head = $apos">\\\'</xsl:when>-->\
<xsl:when test="$head = $quot">\\"</xsl:when>\
<xsl:when test="$head = $nl">\\n</xsl:when>\
<xsl:when test="$head = $cr">\\r</xsl:when>\
<xsl:when test="$head = $sl">\\\\</xsl:when>\
<xsl:otherwise><xsl:value-of select="$head"/></xsl:otherwise>\
</xsl:choose>\
<xsl:call-template name="escapeStringForJson">\
<xsl:with-param name="text" select="$tail"/>\
</xsl:call-template>\
</xsl:if>\
</xsl:template>\
</xsl:stylesheet>';
var works1 = '<?xml version="1.0"?>\
<MyRoot>\
<MyElement>This is "test 1" illustrating escapeStringForJson purpose.</MyElement>\
</MyRoot>';
var works2 = '<?xml version="1.0"?>\
<MyRoot>\
<MyElement>' +
'0123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 100' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 200' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 300' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 400' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 500' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 600' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 700' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 800' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 900' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1000' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1100' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1200' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1300' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1400' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1500' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1600' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1700' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1800' +
' 123456789 123456789 123456789 123456789 123456789 123456789 12345678 1874' +
'</MyElement>\
</MyRoot>';
var nowork = '<?xml version="1.0"?>\
<MyRoot>\
<MyElement>' +
'0123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 100' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 200' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 300' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 400' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 500' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 600' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 700' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 800' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 900' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1000' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1100' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1200' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1300' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1400' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1500' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1600' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1700' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 1800' +
' 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1875' +
'</MyElement>\
</MyRoot>';
console.log(new XMLSerializer().serializeToString(transformXml(works1, xslt)));
console.log(new XMLSerializer().serializeToString(transformXml(works2, xslt))); // these two length-related test-cases do not have any characters that need escaping
console.log(new XMLSerializer().serializeToString(transformXml(nowork, xslt))); // these two length-related test-cases do not have any characters that need escaping
(See your developer console output)
答案 0 :(得分:0)
感谢@ michael.hor257k,我想出了这些。
这将字符串拆分为它找到的第一个"
(或其他搜索到的字符,按顺序)到before
和after
,并递归调用两半的模板。 before
将没有"
,因为我们已经在调用步骤中找到的第一个分割,因此它只能按顺序匹配后面的字符。因此,before
分支肯定会取得进展,因为它耗尽了所搜索的字符列表。 after
分支可以找到另一个相同的字符,但肯定会沿着字符串的长度前进,始终至少前进一个字符。
<xsl:template name="escapeForJson">
<xsl:param name="text"/>
<xsl:variable name="quot">
<xsl:text>"</xsl:text>
</xsl:variable>
<xsl:variable name="nl">
<xsl:text> </xsl:text>
</xsl:variable>
<xsl:variable name="cr">
<xsl:text> </xsl:text>
</xsl:variable>
<xsl:variable name="sl">
<xsl:text>\</xsl:text>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($text, $quot)">
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-before($text,$quot)"/>
</xsl:call-template>
<xsl:text>\"</xsl:text>
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-after($text,$quot)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($text, $nl)">
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-before($text,$nl)"/>
</xsl:call-template>
<xsl:text>\n</xsl:text>
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-after($text,$nl)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($text, $cr)">
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-before($text,$cr)"/>
</xsl:call-template>
<xsl:text>\r</xsl:text>
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-after($text,$cr)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($text, $sl)">
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-before($text,$sl)"/>
</xsl:call-template>
<xsl:text>\\</xsl:text>
<xsl:call-template name="escapeForJson">
<xsl:with-param name="text" select="substring-after($text,$sl)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" disable-output-escaping="yes"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>