<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	
	<xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="utf-8"/>
        
        <xsl:variable name="CONF" select="document('conf_jsonstructure.xml')/conf"/>
	
	<xsl:template match="/">
	    <xsl:apply-templates select="array|object"/>
	</xsl:template>
	
	<xsl:template match="array">
	    <xsl:text>[</xsl:text>
	    <xsl:for-each select="object|array|string|value|raw|xml">
            <xsl:apply-templates select="."/>
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
	    <xsl:text>]</xsl:text>
	</xsl:template>
	
	<xsl:template match="object">
	    <xsl:text>{</xsl:text>
	    <xsl:for-each select="pair">
	         <xsl:apply-templates select="."/>
	        <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>
	    <xsl:text>}</xsl:text>
	</xsl:template>
	
	<xsl:template match="pair">
	    <xsl:text>"jsonstructure-error":"missing name attribute"</xsl:text>
	</xsl:template>
	
	<xsl:template match="pair[@name]" priority="10">
            <xsl:apply-templates select="." mode="name"/>
            <xsl:apply-templates select="object|array|string|value|raw|xml[1]"/>
	</xsl:template>
	
	<xsl:template match="pair[@name and @value]"  priority="20">
	    <xsl:apply-templates select="." mode="name"/>
	    <xsl:call-template name="normalize-value">
                <xsl:with-param name="value" select="@value"/>
            </xsl:call-template>
	</xsl:template>
        
        <xsl:template match="pair" mode="name">
            <xsl:text>"</xsl:text>
            <xsl:call-template name="encode">
                <xsl:with-param name="input" select="normalize-space(@name)"/>
                <xsl:with-param name="type" select="'value'"/>
            </xsl:call-template>
            <xsl:text>"</xsl:text>
            <xsl:text>:</xsl:text>
        </xsl:template>
        
        <xsl:template match="value">
	    <xsl:call-template name="normalize-value">
                <xsl:with-param name="value" select="."/>
            </xsl:call-template>
	</xsl:template>
	
	<xsl:template match="string">
	    <xsl:text>"</xsl:text>
	    <xsl:call-template name="encode">
                <xsl:with-param name="input" select="text()"/>
                <xsl:with-param name="type" select="'string'"/>
            </xsl:call-template>
	    <xsl:text>"</xsl:text>
	</xsl:template>
        
        <xsl:template match="raw">
            <xsl:value-of select="."/>
	</xsl:template>
        
        <xsl:template match="xml">
	    <xsl:text>"</xsl:text>
	    <xsl:apply-templates select="*|text()" mode="xml"/>
	    <xsl:text>"</xsl:text>
	</xsl:template>
	
	<xsl:template match="text()" mode="xml">
            <xsl:call-template name="encode">
                <xsl:with-param name="input" select="."/>
                <xsl:with-param name="type" select="'xml'"/>
            </xsl:call-template>
	</xsl:template>
	
	<xsl:template match="*" mode="xml">
	    <xsl:text>&lt;</xsl:text>
	    <xsl:value-of select="name()"/>
	    <xsl:for-each select="@*">
                <xsl:text> </xsl:text>
                <xsl:value-of select="name()"/>
                <xsl:text>=\"</xsl:text>
                <xsl:call-template name="encode">
                    <xsl:with-param name="input" select="."/>
                    <xsl:with-param name="name" select="'text-in-string'"/>
                </xsl:call-template>
                <xsl:text>\"</xsl:text>
            </xsl:for-each>
            <xsl:choose>
                <xsl:when test="count(*|text()) = 0"><xsl:text>/&gt;</xsl:text></xsl:when>
                <xsl:otherwise>
                    <xsl:text>&gt;</xsl:text>
                    <xsl:apply-templates select="*|text()" mode="string"/>
                    <xsl:text>&lt;/</xsl:text>
                    <xsl:value-of select="name()"/>
                    <xsl:text>&gt;</xsl:text>
                </xsl:otherwise>
            </xsl:choose>
	</xsl:template>
        
        <xsl:template name="normalize-value">
            <xsl:param name="value"/>
            <xsl:variable name="cleanvalue" select="normalize-space($value)"/>
            <xsl:choose>
                <xsl:when test="(string(number($cleanvalue)) = 'NaN' or (substring($cleanvalue , string-length($cleanvalue), 1) = '.') or (substring($cleanvalue, 1, 1) = '0') and not($cleanvalue = '0')) and not($cleanvalue = 'false') and not($cleanvalue = 'true') and not($cleanvalue = 'null')">
                    <xsl:text>"</xsl:text>
                    <xsl:call-template name="encode">
                        <xsl:with-param name="input" select="$cleanvalue"/>
                        <xsl:with-param name="type" select="'value'"/>
                    </xsl:call-template>
                    <xsl:text>"</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$cleanvalue"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>

	<xsl:template name="encode">
            <xsl:param name="input"/>
            <xsl:param name="type">value</xsl:param>
            <xsl:param name="index">1</xsl:param>

            <xsl:variable name="text">
                <xsl:call-template name="replace-string">
                    <xsl:with-param name="input" select="$input"/>
                    <xsl:with-param name="type" select="$type"/>
                    <xsl:with-param name="src" select="$CONF/search[@type=$type]/replace[$index]/@src"/>
                    <xsl:with-param name="dst" select="$CONF/search[@type=$type]/replace[$index]/@dst"/>
                </xsl:call-template>
            </xsl:variable>

            <xsl:choose>
                <xsl:when test="$index &lt; count($CONF/search[@type=$type]/replace)">
                    <xsl:call-template name="encode">
                        <xsl:with-param name="input" select="$text"/>
                        <xsl:with-param name="type" select="$type"/>
                        <xsl:with-param name="index" select="$index + 1"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$text"/>
                </xsl:otherwise>
            </xsl:choose>
	</xsl:template>
        
        <xsl:template name="replace-string">
		<xsl:param name="input"/>
		<xsl:param name="src"/>
		<xsl:param name="dst"/>
		<xsl:choose>
                    <xsl:when test="contains($input, $src)">
                        <xsl:value-of select="concat(substring-before($input, $src), $dst)"/>
                        <xsl:call-template name="replace-string">
                            <xsl:with-param name="input" select="substring-after($input, $src)"/>
                            <xsl:with-param name="src" select="$src"/>
                            <xsl:with-param name="dst" select="$dst"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$input"/>
                    </xsl:otherwise>
		</xsl:choose>
	</xsl:template>
	
</xsl:stylesheet>
