XSL template for converting XML to JSON I used saxon v9 to profile an XSL transformation which converts XML to JSON. The profiler tells me that the function which escapes certain characters takes about 70% of the total processing time. The conversion is important because otherwise the created JSON file will be invalid because of characters that break the strings.

java -jar saxon9he.jar -xsl:jsontransform.xslt -s:input.xml -o:output.json -TP


The "method" used to escape the values looks like this:

&lt;xsl:template name="escapejson"&gt;
        &lt;xsl:param name="string"/&gt;
        &lt;xsl:sequence select="replace(
                              replace(
                              replace(
                              replace(
                              replace( 
                              replace(
                              replace(
                              replace(
                              replace($string, '\\','\\\\'), 
                              '/', '\\/'),
                              '&amp;quot;', '\\&amp;quot;'),
                              '&amp;#xA;','\\n'),
                              '&amp;#xD;','\\r'),      
                              '&amp;#x9;','\\t'),  
                              '\n','\\n'),
                              '\r','\\r'),
                              '\t','\\t')"/&gt;
    &lt;/xsl:template&gt;


Unfortunately, my XSL knowledge is too limited to create an optimum solution on my own. I assume the repeated call of replace is quite inefficient but don't know how to do it better.
I can believe it when the replace is the problem... it's creating a mess of nested code that's creating a lot of intermediate string values.

There's not much I can see to improve, though. The nesting can be reduced by combining a few of replaces...:

replace(.... , '\n|&amp;#xA', '\\n')


Doing the same for \t and \r will reduce six calls to just three.

Additionally, I would consider wrapping the entire replace function in a matches call, that matches any of the patterns you are searching for, so you only need to do the full replacement call stack on values that actually require it. A large matches for all replaced values will, depending on how often values are actually required to be replaced, save time.