Search code examples
jsonxslt-1.0carriage-return

How to replace return (
 | 
) by the string "\n" in xslt 1.0 ? [XML multiline base64 to json]


I got a xml that I need to turn into a json. I'm mostly fine except with a base64 multiline

<file>TU0...AAA
FOO...BCD
FOO...012
FOO...ZYX</file>

In json multiline is not possible, this should be rewritten in 1 line only as

"file":"TU0...AAA\nFOO...BCD\nFOO...012\nFOO...ZYX" 

With "real" two-char string "\n" to concatenate each line.

Can I do that in xslt 1.0 ?

I know I can use translate but that's for one char only. I'll try

translate(.,'&#10;',' ') 

This will replace returns by space and maybe this won't break the base64 decoding of the json.

But, if i want to do it the "right way", I guess I'll need custom funcs. In my case returns seems to be " ". But if someone comes with a solution that works with all combinations ( ) that would be great.

My primary target is chrome web browser but running fine in all browsers would be great.


Solution

  • If you just want to get rid of the linefeeds you could use the normalize-space($string)function, e.g.:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
        exclude-result-prefixes="xd"
        version="1.0">
        <xd:doc scope="stylesheet">
            <xd:desc>
                <xd:p><xd:b>Created on:</xd:b> Apr 22, 2020</xd:p>
                <xd:p><xd:b>Author:</xd:b> bwb</xd:p>
                <xd:p>generates a normalized text output of the file element</xd:p>
            </xd:desc>
        </xd:doc>
    
        <xsl:output method="text"/>
    
        <xsl:template match="/">
            <xsl:apply-templates select="file"/>
        </xsl:template>
    
        <xsl:template match="file">
            <xsl:value-of select="normalize-space(.)"/>
        </xsl:template>
    
    </xsl:stylesheet>
    

    You could then still replace the whitespaces by something else( forJSON maybe with ,)

    If you definitely want the \nthough, you could try the following stylesheet:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:math="http://www.w3.org/2005/xpath-functions/math"
        xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
        exclude-result-prefixes="xs math xd"
        version="1.0">
        <xd:doc scope="stylesheet">
            <xd:desc>
                <xd:p><xd:b>Created on:</xd:b> Apr 22, 2020</xd:p>
                <xd:p><xd:b>Author:</xd:b> bwb</xd:p>
                <xd:p>Override default text() template by adding a search and replace funtionality</xd:p>
            </xd:desc>
        </xd:doc>
    
        <xsl:output method="text"/>
    
        <xd:doc scope="component">
            <xd:desc>The string that should be searched and replaced by $param-replaceString</xd:desc>
        </xd:doc>
        <xsl:param name="param-searchString" select="'&#10;    '"/><!-- actually you also wnat to replace the whitespaces, that's why the searchString looks so  strange -->
    
        <xd:doc>
            <xd:desc>The string that replace any occurence of $param-searchString</xd:desc>
        </xd:doc>
        <xsl:param name="param-replaceString" select="'\n'"/>
    
        <xd:doc scope="component">
            <xd:desc>Override for default text() template testing for $param-searchString presence and calling replace template</xd:desc>
        </xd:doc>
        <xsl:template match="text()">
            <xsl:choose>
                <xsl:when test="contains(., $param-searchString)">
                    <xsl:call-template name="replace">
                        <xsl:with-param name="InputString" select="."/>
                        <xsl:with-param name="searchString" select="$param-searchString"/>
                        <xsl:with-param name="replaceString" select="$param-replaceString"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    
        <xsl:template name="replace">
            <xsl:param name="InputString"/>
            <xsl:param name="searchString"/>
            <xsl:param name="replaceString"/>
    
            <xsl:choose>
                <xsl:when test="contains($InputString, $searchString)">
                    <xsl:variable name="token-before-first-match" select="substring-before($InputString, $searchString)"/>
                    <xsl:variable name="token-after-first-match" select="substring-after(., concat($token-before-first-match, $searchString))"/>
                    <xsl:value-of select="concat($token-before-first-match, $replaceString)"/>
                    <xsl:choose>
                        <xsl:when test="contains($token-after-first-match, $searchString)">
                            <xsl:call-template name="replace">
                                <xsl:with-param name="InputString" select="$token-after-first-match"/>
                                <xsl:with-param name="searchString" select="$searchString"/>
                                <xsl:with-param name="replaceString" select="$replaceString"/>
                            </xsl:call-template>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:value-of select="$token-after-first-match"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$InputString"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    
    </xsl:stylesheet>