I have a XSL associate with an XML file. This XSL aim to create Mysql queries but in my XML I had some special characters like apostroph ' which break my queries. Do you know how I can sanitize my XSL template in order to have safe queries?
Example of my XML file
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="fnac.xsl"?>
<products xmlns="http://zanox.com/productdata/exportservice/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://zanox.com/productdata/exportservice/v1 http://productdata.zanox.com/exportservice/schema/export-1.1.xsd">
<product>
<name>jack o'connor</name>
<program>3467</program>
</product>
</products>
And my XSL file :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v1="http://zanox.com/productdata/exportservice/v1">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//v1:product"/>
</xsl:template>
<xsl:template match="v1:product">
<xsl:text>insert into fnac (name, program) values(</xsl:text>
<xsl:value-of select="./v1:name"/>
<xsl:text>,'</xsl:text>
<xsl:value-of select="./v1:program"/>
<xsl:text>'); </xsl:text>
</xsl:template>
</xsl:stylesheet>
Thanks for your inputs!
If you want to remove apostrope from your XML file, you should use this xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v1="http://zanox.com/productdata/exportservice/v1">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//v1:product"/>
</xsl:template>
<xsl:template match="v1:product">
<xsl:text>insert into fnac (name, program) values(</xsl:text>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="./v1:name"/>
<xsl:with-param name="from">'</xsl:with-param>
<xsl:with-param name="to" select="' '"/>
</xsl:call-template>
<xsl:text>,'</xsl:text>
<xsl:value-of select="./v1:program"/>
<xsl:text>'); </xsl:text>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains($text, $from)">
<xsl:variable name="before" select="substring-before($text, $from)"/>
<xsl:variable name="after" select="substring-after($text, $from)"/>
<xsl:copy-of select="$before"/>
<xsl:value-of select="$to" disable-output-escaping="yes"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
which would generate output:
insert into fnac (name, program) values(jack o connor,'3467');
If you only like/need to replace the apostrope , this could be done lot easier with translate().
Try this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v1="http://zanox.com/productdata/exportservice/v1">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//v1:product"/>
</xsl:template>
<xsl:template match="v1:product">
<xsl:text>insert into fnac (name, program) values(</xsl:text>
<xsl:value-of select='translate(./v1:name,"'", " ")'/>
<xsl:text>,'</xsl:text>
<xsl:value-of select="./v1:program"/>
<xsl:text>'); </xsl:text>
</xsl:template>
</xsl:stylesheet>
Related
I want to convert a XML to JSON using XSLT. But I am facing few issues.
Input XML
<notifications xmlns="http://soap.sforce.com/2005/09/outbound">
<OrganizationId>123</OrganizationId>
<ActionId>123</ActionId>
<SessionId xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<EnterpriseUrl>qwe</EnterpriseUrl>
<PartnerUrl>qwe</PartnerUrl>
<Notification>
<Id>123</Id>
<sObject xsi:type="sf:Opportunity" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
<sf:Id>ao123</sf:Id>
<sf:Amount>60000.0</sf:Amount>
<sf:CreatedDate>2014-11-26T14:45:52.000Z</sf:CreatedDate>
<sf:IsClosed>false</sf:IsClosed>
</sObject>
</Notification>
</notifications>
Expected Output JSON
{
"notifications": {
"OrganizationId": "123",
"ActionId": "123",
"SessionId": {
"#nil": "true"
},
"EnterpriseUrl": "qwe",
"PartnerUrl": "qwe",
"Notification": [
{
"Id": "ao123",
"sObject": {
"#type": "sf:Opportunity",
"Id": "ao123",
"Amount": "60000.0",
"CreatedDate": "2014-11-26T14:45:52.000Z",
"IsClosed": "false"
}
}
]
}
}
From this answer I got XSLT and I have tried it. This is the XSLT code I have tried. Fiddle link
<?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"
exclude-result-prefixes="#all"
xmlns="http://www.w3.org/2005/xpath-functions"
expand-text="yes"
version="3.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="json-xml">
<xsl:apply-templates/>
</xsl:variable>
<xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
</xsl:template>
<xsl:template match="*[not(*)]">
<string key="{local-name()}">{.}</string>
</xsl:template>
<xsl:template match="*[*]">
<xsl:param name="key" as="xs:boolean" select="false()"/>
<map>
<xsl:if test="$key">
<xsl:attribute name="key" select="local-name()"/>
</xsl:if>
<xsl:for-each-group select="*" group-by="node-name()">
<xsl:choose>
<xsl:when test="current-group()[2]">
<array key="{local-name()}">
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="false()"/>
</xsl:apply-templates>
</array>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="true()"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</map>
</xsl:template>
</xsl:stylesheet>
So below are few issues which I am facing
notifications node is missing in json output, it is the root node in the xml.
Notification should be a json array even if I receive one
item in XML
Please note that I don't want to hard code node names other than notifications and Notification in XSLT code as I may receive different nodes under node Notification.
I am looking for XSLT which can handle my requirements
Some of the requirements (outer map/JSON object, always making Notification an array) can of course be inserted into the XSLT code by modifying what you linked to (please make sure next time you show the XSLT in the question as well):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
xmlns="http://www.w3.org/2005/xpath-functions"
expand-text="yes"
version="3.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="json-xml">
<map>
<xsl:apply-templates/>
</map>
</xsl:variable>
<xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
</xsl:template>
<xsl:template match="*[not(*)]">
<string key="{local-name()}">{.}</string>
</xsl:template>
<xsl:template match="*[*]">
<xsl:param name="key" as="xs:boolean" select="true()"/>
<map>
<xsl:if test="$key">
<xsl:attribute name="key" select="local-name()"/>
</xsl:if>
<xsl:for-each-group select="*" group-by="node-name()">
<xsl:choose>
<xsl:when test="current-group()[2] or current-grouping-key() = QName('http://soap.sforce.com/2005/09/outbound', 'Notification')">
<array key="{local-name()}">
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="false()"/>
</xsl:apply-templates>
</array>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="true()"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</map>
</xsl:template>
</xsl:stylesheet>
The code you grabbed from another question/answer I think was not written with XML having elements with attributes in mind; I have tried to adapt it below with
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
xmlns="http://www.w3.org/2005/xpath-functions"
expand-text="yes"
version="3.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="json-xml">
<map>
<xsl:apply-templates/>
</map>
</xsl:variable>
<xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
</xsl:template>
<xsl:template match="*[not(*)]">
<string key="{local-name()}">{.}</string>
</xsl:template>
<xsl:template match="#*">
<string key="#{local-name()}">{.}</string>
</xsl:template>
<xsl:template match="*[* or #*]">
<xsl:param name="key" as="xs:boolean" select="true()"/>
<map>
<xsl:if test="$key">
<xsl:attribute name="key" select="local-name()"/>
</xsl:if>
<xsl:apply-templates select="#*"/>
<xsl:for-each-group select="*" group-by="node-name()">
<xsl:choose>
<xsl:when test="current-group()[2] or current-grouping-key() = QName('http://soap.sforce.com/2005/09/outbound', 'Notification')">
<array key="{local-name()}">
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="false()"/>
</xsl:apply-templates>
</array>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()">
<xsl:with-param name="key" select="true()"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</map>
</xsl:template>
</xsl:stylesheet>
That seems to give the wanted attributes as #name properties of a JSON object/map for your sample; I can't guarantee it will work in general.
it's been days trying to perform a transformation to get a JSON file from XML documents. My xml doc have different levels of sub nodes, all examples I found on internet don't catch my case.
Here is my xml example:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo id="1" group="B" />
<foo id="2" group="A" />
<foo id="3", group="A">
<foo id="4" group="A" />
<foo id="5" group="A">
<foo id="6" group="A" />
<foo id="7" group="A" />
<foo id="8" group="A" />
</foo>
</foo>
<foo id="9" group="A"></foo>
</root>
desired JSON:
{
"B": {
"id": 1
},
"A": {
"id": 2
},
"A": [{
"id": 4
},
{
"A": [{
"id": 6
},
{
"id": 7
},
{
"id": 8
}
]
}
],
"A": {
"id": 9
}
}
Means whenever I have nested <foo> elements, child elements are grouped with the parent element, and so on.
I tried some xsl code (see1 and see2) and failed to make them work for my case.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="root">
<xsl:text>{</xsl:text>
<xsl:apply-templates select="//foo"/>
<xsl:text>}</xsl:text>
</xsl:template>
<xsl:template match="//foo">
<xsl:choose>
<xsl:when test=" count(ancestor::foo) = 1 and child::foo"/>
<xsl:when test="foo[child::foo]"/>
<xsl:otherwise>
<xsl:text>"</xsl:text><xsl:value-of select="#group"/><xsl:text>"</xsl:text>:<xsl:text> {
</xsl:text>
<xsl:text> "</xsl:text><xsl:value-of select="#id/name()"/><xsl:text>"</xsl:text>:<xsl:value-of select=" concat(' ',#id)"/>
<xsl:text>
},</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Please Check this code:
<?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" exclude-result-prefixes="xs" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="root">
<xsl:text>{</xsl:text>
<xsl:text>
</xsl:text>
<xsl:for-each select="foo">
<xsl:if test="not(child::foo)">
<xsl:text> "</xsl:text><xsl:value-of select="#group"/><xsl:text>": </xsl:text><xsl:text>{</xsl:text><xsl:text>
</xsl:text>
<xsl:text> "id": </xsl:text><xsl:value-of select="#id"/><xsl:text>
</xsl:text>
<xsl:text> }</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:for-each select="foo">
<xsl:if test="not(child::foo)">
<xsl:text> "</xsl:text><xsl:value-of select="#group"/><xsl:text>": </xsl:text><xsl:if test="parent::foo"><xsl:text>[</xsl:text></xsl:if><xsl:text>{</xsl:text><xsl:text>
</xsl:text>
<xsl:text> "id": </xsl:text><xsl:value-of select="#id"/><xsl:text>
</xsl:text>
<xsl:text> },</xsl:text><xsl:text>
</xsl:text>
<xsl:text> {</xsl:text><xsl:text>
</xsl:text>
<xsl:text> "</xsl:text><xsl:value-of select="#group"/><xsl:text>": </xsl:text><xsl:text>[</xsl:text><xsl:text>
</xsl:text>
</xsl:if>
<!-- <xsl:text> "</xsl:text><xsl:value-of select="#group"/><xsl:text>": </xsl:text><xsl:text>[{</xsl:text><xsl:text>
</xsl:text>-->
<xsl:for-each select="foo">
<xsl:text> {</xsl:text><xsl:text>
</xsl:text>
<xsl:text> "id": </xsl:text><xsl:value-of select="#id"/><xsl:text>
</xsl:text>
<xsl:text> }</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if><xsl:text>
</xsl:text>
<xsl:if test="position()=last()">
<xsl:text> ]</xsl:text><xsl:text>
</xsl:text>
</xsl:if>
<xsl:if test="position()=last()">
<xsl:text> }</xsl:text><xsl:text>
</xsl:text>
</xsl:if>
<xsl:if test="position()=last()">
<xsl:text>],</xsl:text><xsl:text>
</xsl:text>
</xsl:if>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
<xsl:text>}</xsl:text>
</xsl:template>
</xsl:stylesheet>
It is not quite clear which result you want as the desired "JSON" has duplicated properties if there are various foo group="A" elements but in general of XML to JSON generation you can use XSLT 3 with support for XPath 3.1 maps and arrays (https://www.w3.org/TR/xpath-31/#id-maps-and-arrays) and the json output method or the xml-to-json function (https://www.w3.org/TR/xslt-30/#json, https://www.w3.org/TR/xslt-30/#func-xml-to-json), that way you have two ways of creating JSON and outputting it, you can either transform your XML directly to XPath 3.1 maps/arrays and serialize them with <xsl:output method="json"/> or you can use the usual XSLT processing to transform your input XML to the JSON XML representation the xml-to-json function expects and apply it to get the JSON as text.
Here is an example of the first approach:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-skip"/>
<xsl:strip-space elements="*"/>
<xsl:output method="json" indent="yes"/>
<xsl:template match="*[*]">
<xsl:map>
<xsl:for-each-group select="foo" group-by="#group">
<xsl:map-entry key="string(current-grouping-key())">
<xsl:choose>
<xsl:when test="not(tail(current-group()))">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="group-transform" as="map(*)*">
<xsl:apply-templates select="current-group()"/>
</xsl:variable>
<xsl:sequence select="array { $group-transform }"/>
</xsl:otherwise>
</xsl:choose>
</xsl:map-entry>
</xsl:for-each-group>
</xsl:map>
</xsl:template>
<xsl:template match="*[not(*)]">
<xsl:sequence select="map { 'id' : data(#id) }"/>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/6r5Gh3i
And here one of the second:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all"
xmlns="http://www.w3.org/2005/xpath-functions"
expand-text="yes"
version="3.0">
<xsl:mode on-no-match="shallow-skip"/>
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:variable name="json-xml">
<xsl:apply-templates/>
</xsl:variable>
<xsl:template match="/">
<xsl:sequence select="xml-to-json($json-xml, map { 'indent' : true() })"/>
</xsl:template>
<xsl:template match="*[*]">
<map>
<xsl:for-each-group select="foo" group-by="string(#group)">
<xsl:choose>
<xsl:when test="not(tail(current-group()))">
<map key="{current-grouping-key()}">
<string key="id">{#id}</string>
</map>
</xsl:when>
<xsl:otherwise>
<array key="{current-grouping-key()}">
<xsl:apply-templates select="current-group()"/>
</array>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</map>
</xsl:template>
<xsl:template match="*[not(*)]">
<map>
<string key="id">{#id}</string>
</map>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/6r5Gh3i/5
XSLT 3 is available using Saxon 9.8 or 9.9 HE for the Java platform on Sourceforge and Maven https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE/9.9.1-2 and for the .NET platform on NuGet https://www.nuget.org/packages/Saxon-HE/.
My xml:
<workorder>
<specifications>
<hpath>94 \ 72</hpath>
<classdesc></classdesc>
</specifications>
</workorder>
my xslt:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="workorder">
<xsl:apply-templates select="specifications" />
</xsl:template>
<xsl:template match="specifications">
<xsl:text>{
"Hierarchy Path"="</xsl:text>
<xsl:value-of select="translate(//workorder/specifications/hpath,'\','\\')" />
<xsl:text>"
}</xsl:text>
</xsl:template>
</xsl:stylesheet>
Expecting output is:
{
"Hierarchy Path"="94 \\ 72"
}
Current output is :
{
"Hierarchy Path"="94 \ 72"
}
Problem is: When I send json format as "Current output", not a valid json format.
If I send as "Expected output", it is a valid json format.
Please help. Thanks in advance.
With XSLT 1.0 you need a recursive approach.
You may try something like this named template.
<xsl:template name="jsonescape">
<xsl:param name="str" select="."/>
<xsl:choose>
<xsl:when test="contains($str, '\')">
<xsl:value-of select="concat(substring-before($str, '\'), '\\' )"/>
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="substring-after($str, '\')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
And call it with your strings(for example).
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="//workorder/specifications/hpath"/>
</xsl:call-template>
I have an xml coming as below
<Envelope>
<content>
<feild1>1</feild1>
....
<feild10>10<feild10>
</content>
</Envelope>
but want the xml to be (add the namespace prefix as xs1 and content lower case c to Upper case "C"
<Envelope>
<Content> <!-- Note the lower case c chnaged to Upper Case --->
<xs1:feild1>1</xs1:feild1> <!-- and for the feild, xs1 is added as prefix -->
....
<xs1:feild10>10</xs1:feild10>
</Content>
</Envelope>
Please help looking for XSLT 1.0
Here is my XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs1="https://temp">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="https://temp">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{name}"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Hope this helps
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs1="https://temp">
<xsl:template match="/">
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<Envelope>
<xsl:for-each select="Envelope/*">
<xsl:variable name="root" select="local-name(.)"/>
<xsl:variable name="temp" select="translate($root,$smallcase,$uppercase)"/>
<xsl:variable name="temp2" select="concat(substring($temp,1,1),translate(substring($temp,2,string-length($temp)),$uppercase,$smallcase))"/>
<xsl:element name="{$temp2}">
<xsl:for-each select="child::*">
<xsl:element name="xs1:{local-name(.)}" namespace="https://temp">
<xsl:value-of select="node()"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</Envelope>
</xsl:template>
</xsl:stylesheet>
We are using XSLT to translate a RIXML file to XML. Our RIXML contains the following text:
<Title><![CDATA[Looking into the future: Reiterate ‘Buy’]]></Title>
8216 is a left quote and 8217 is a right quote.
How would I replace these HTML codes with their plain text representation, or more simply, just a single quote? This is XSLT version 1.0.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vQ2">""</xsl:variable>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select=
"translate(.,'‘’',$vQ2)"/>
</xsl:template>
</xsl:stylesheet>
I came upon this function which worked well for me. I call it to replace all the characters I need to:
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>