]> Pierre Choffet | Git repositories - banq_wikidata.git/commitdiff
Add stylesheet to export titles/subtitles into TSV file
authorPierre Choffet <peuc@wanadoo.fr>
Mon, 8 Dec 2025 15:13:43 +0000 (10:13 -0500)
committerPierre Choffet <peuc@wanadoo.fr>
Mon, 8 Dec 2025 15:13:43 +0000 (10:13 -0500)
README
export_strings.xslt [new file with mode: 0644]

diff --git a/README b/README
index 5d3770da25d598b44f2deb0a0f6cb6337acb0867..c653ae3c36c7d212aa2bd4b55bc0b1899a931d24 100644 (file)
--- a/README
+++ b/README
@@ -1,6 +1,5 @@
 Ce dépôt contient tous les outils utilisés pour convertir les données de
-Bibliothèque et Archives nationales du Québec (BAnQ) et de les publier dans
-Wikidata.
+Bibliothèque et Archives nationales du Québec (BAnQ) et les publier dans Wikidata.
 
 
 L’environnement d’utilisation nécessite la disponibilité des outils suivants :
@@ -23,3 +22,7 @@ Les outils disponibles sont les suivants :
   - merge_marcxml.xslt
     Fusionner deux fichiers au format MARCXML en supprimant les entrées
     présentes en plusieurs exemplaires.
+
+  - export_strings.xslt
+    Exporte les chaînes de titres et sous titres pour les entrées
+    bibliographiques vers un fichier TSV.
diff --git a/export_strings.xslt b/export_strings.xslt
new file mode 100644 (file)
index 0000000..c3a7e28
--- /dev/null
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim"
+                xmlns:xml="http://www.w3.org/XML/1998/namespace"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <!-- export_strings.xslt - Export strings that require human check
+    Copyright (C) 2025  Pierre Choffet
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of version 3 of the GNU General Public License as
+    published by the Free Software Foundation.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    -->
+    
+       <xsl:output method="text" encoding="utf-8" />
+       
+       <xsl:param name="strings-fix-path" />
+       <xsl:param name="target" />
+       
+       <xsl:variable name="strings-fix-doc" select="document($strings-fix-path)" />
+       
+       <xsl:key name="fix-record" match="/records/record" use="@id" />
+       <xsl:key name="fix-record-title" match="/records/record/fix[@type='title']" use="../@id" />
+       <xsl:key name="fix-record-title-source" match="/records/record/fix[@type='title']/@source" use="../../@id" />
+       <xsl:key name="fix-record-title-lang" match="/records/record/fix[@type='title']/@xml:lang" use="../../@id" />
+       <xsl:key name="fix-record-subtitle" match="/records/record/fix[@type='subtitle']" use="../@id" />
+       <xsl:key name="fix-record-subtitle-source" match="/records/record/fix[@type='subtitle']/@source" use="../../@id" />
+       <xsl:key name="fix-record-subtitle-lang" match="/records/record/fix[@type='subtitle']/@xml:lang" use="../../@id" />
+       <xsl:key name="fix-record-first-name" match="/records/record/fix[@type='first-name']" use="../@id" />
+       <xsl:key name="fix-record-last-name" match="/records/record/fix[@type='last-name']" use="../@id" />
+       <xsl:key name="fix-record-name-source" match="/records/record/fix[@type='name']/@source" use="../../@id" />
+       <xsl:key name="fix-record-nickname" match="/records/record/fix[@type='nickname']" use="../@id" />
+       <xsl:key name="fix-record-nickname-source" match="/records/record/fix[@type='nickname']/@source" use="../../@id" />
+       
+       <xsl:template match="text()" />
+       
+       <xsl:template match="/marc:collection">
+               <xsl:choose>
+                       <xsl:when test="$target = 'bibliographic'">
+                               <xsl:text>ID    Titre original  Langue du titre Titre corrigé  Sous-titre original     Langue du sous-titre    Sous-titre corrigé</xsl:text>
+                               <xsl:text>&#10;</xsl:text>
+                               <xsl:apply-templates select="marc:record[substring(marc:leader, 7, 1) != 'z']" mode="bibliographic" />
+                       </xsl:when>
+                       <xsl:when test="$target = 'person'">
+                               <xsl:text>ID    Nom original    Prénom Nom     Pseudonyme original     Pseudonyme</xsl:text>
+                               <xsl:text>&#10;</xsl:text>
+                               <xsl:apply-templates select="marc:record[substring(marc:leader, 7, 1) = 'z' and marc:datafield[@tag='100']]" mode="person" />
+                       </xsl:when>
+                       <xsl:when test="$target = 'corporate'">
+                               <xsl:apply-templates select="marc:record[substring(marc:leader, 7, 1) = 'z' and marc:datafield[@tag='110']]" mode="corporate" />
+                       </xsl:when>
+                       <xsl:when test="$target = 'meeting'">
+                               <xsl:apply-templates select="marc:record[substring(marc:leader, 7, 1) = 'z' and marc:datafield[@tag='111']]" mode="meeting" />
+                       </xsl:when>
+                       <xsl:otherwise>
+                               <xsl:message terminate="yes">Paramètre « target » invalide. Les valeurs autorisées sont « bibliographic », « person », « corporate » ou « meeting ».</xsl:message>
+                       </xsl:otherwise>
+               </xsl:choose>
+       </xsl:template>
+       
+       <!-- Notices bibliographique -->
+       <xsl:template match="/marc:collection/marc:record[substring(marc:leader, 7, 1) != 'z']" mode="bibliographic">
+               <xsl:variable name="bibliographic-leader" select="marc:controlfield[@tag='001']" />
+               <xsl:variable name="source-title">
+                       <xsl:choose>
+                               <xsl:when test="marc:datafield[@tag='130']">
+                                       <xsl:apply-templates select="marc:datafield[@tag='130']" mode="title" />
+                               </xsl:when>
+                               <xsl:when test="marc:datafield[@tag='245']">
+                                       <xsl:apply-templates select="marc:datafield[@tag='245']" mode="title" />
+                               </xsl:when>
+                               <xsl:when test="marc:datafield[@tag='246']">
+                                       <xsl:apply-templates select="marc:datafield[@tag='246']" mode="title" />
+                               </xsl:when>
+                               <xsl:when test="marc:datafield[@tag='740']">
+                                       <xsl:apply-templates select="marc:datafield[@tag='740']" mode="title" />
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:message terminate="yes">
+                                               <xsl:text xml:lang="fr">Aucun titre n’a été trouvé pour la notice </xsl:text>
+                                               <xsl:value-of select="$bibliographic-leader" />
+                                               <xsl:text xml:lang="fr">.</xsl:text>
+                                       </xsl:message>
+                               </xsl:otherwise>
+                       </xsl:choose>
+               </xsl:variable>
+               <xsl:variable name="source-title-quoted">
+                       <xsl:call-template name="string-replace-all">
+        <xsl:with-param name="text" select="$source-title" />
+        <xsl:with-param name="replace" select="'&quot;'" />
+        <xsl:with-param name="by" select="'&quot;&quot;'" />
+                       </xsl:call-template>
+               </xsl:variable>
+               <xsl:variable name="source-subtitle">
+                       <xsl:apply-templates select="marc:datafield[@tag='245' and marc:subfield[@code='b']]" mode="subtitle" />
+               </xsl:variable>
+               <xsl:variable name="source-subtitle-quoted">
+                       <xsl:call-template name="string-replace-all">
+        <xsl:with-param name="text" select="$source-subtitle" />
+        <xsl:with-param name="replace" select="'&quot;'" />
+        <xsl:with-param name="by" select="'&quot;&quot;'" />
+                       </xsl:call-template>
+               </xsl:variable>
+               
+               <xsl:variable name="fix-title">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-title', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-title-quoted">
+                       <xsl:call-template name="string-replace-all">
+        <xsl:with-param name="text" select="$fix-title" />
+        <xsl:with-param name="replace" select="'&quot;'" />
+        <xsl:with-param name="by" select="'&quot;&quot;'" />
+                       </xsl:call-template>
+               </xsl:variable>
+               <xsl:variable name="fix-title-source">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-title-source', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-title-source-quoted">
+                       <xsl:call-template name="string-replace-all">
+        <xsl:with-param name="text" select="$fix-title-source" />
+        <xsl:with-param name="replace" select="'&quot;'" />
+        <xsl:with-param name="by" select="'&quot;&quot;'" />
+                       </xsl:call-template>
+               </xsl:variable>
+               <xsl:variable name="fix-title-lang">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-title-lang', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-subtitle">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-subtitle', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-subtitle-quoted">
+                       <xsl:call-template name="string-replace-all">
+        <xsl:with-param name="text" select="$fix-subtitle" />
+        <xsl:with-param name="replace" select="'&quot;'" />
+        <xsl:with-param name="by" select="'&quot;&quot;'" />
+                       </xsl:call-template>
+               </xsl:variable>
+               <xsl:variable name="fix-subtitle-source">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-subtitle-source', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-subtitle-source-quoted">
+                       <xsl:call-template name="string-replace-all">
+        <xsl:with-param name="text" select="$fix-subtitle-source" />
+        <xsl:with-param name="replace" select="'&quot;'" />
+        <xsl:with-param name="by" select="'&quot;&quot;'" />
+                       </xsl:call-template>
+               </xsl:variable>
+               <xsl:variable name="fix-subtitle-lang">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-subtitle-lang', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               
+               <!-- Export title strings -->
+               <xsl:choose>
+                       <!-- If corresponding entry is found in fix document -->
+                       <xsl:when test="$fix-title != '' and $fix-title-source = $source-title">
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$bibliographic-leader" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$fix-title-lang" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$fix-title-quoted" />
+                               <xsl:text>"</xsl:text>
+                       </xsl:when>
+                       <xsl:when test="$fix-title != '' and $fix-title-source != $source-title">
+                               <xsl:message terminate="no">
+                                       <xsl:text>Un correctif pour la notice de l’entrée </xsl:text>
+                                       <xsl:value-of select="$bibliographic-leader" />
+                                       <xsl:text> existe, mais le titre dans la notice a été modifié depuis. La valeur de correction est ignorée.</xsl:text>
+                               </xsl:message>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$bibliographic-leader" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$source-title-quoted" />
+                               <xsl:text>"     </xsl:text>
+                               <!-- Empty column for fixed title lang here -->
+                               <xsl:text>      </xsl:text>
+                               <!-- Empty column for fixed title here -->
+                               <xsl:text>      </xsl:text>
+                       </xsl:when>
+                       <!-- No corresponding entry found in fix document -->
+                       <xsl:otherwise>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$bibliographic-leader" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$source-title-quoted" />
+                               <xsl:text>"     </xsl:text>
+                               <!-- Empty column for fixed title lang here -->
+                               <xsl:text>      </xsl:text>
+                               <!-- Empty column for fixed title here -->
+                               <xsl:text>      </xsl:text>
+                       </xsl:otherwise>
+               </xsl:choose>
+               
+               <!-- Export subtitle strings -->
+               <xsl:choose>
+                       <!-- If corresponding entry is found in fix document -->
+                       <xsl:when test="$fix-subtitle != '' and $fix-subtitle-source = $source-subtitle">
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$source-subtitle-quoted" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$fix-subtitle-lang" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$fix-subtitle-quoted" />
+                               <xsl:text>"</xsl:text>
+                       </xsl:when>
+                       <xsl:when test="$fix-subtitle != '' and $fix-subtitle-source != $source-subtitle">
+                               <xsl:message terminate="no">
+                                       <xsl:text>Un correctif pour la notice de l’entrée </xsl:text>
+                                       <xsl:value-of select="$bibliographic-leader" />
+                                       <xsl:text> existe, mais le sous-titre dans la notice a été modifié depuis. La valeur de correction est ignorée.</xsl:text>
+                               </xsl:message>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$source-subtitle-quoted" />
+                               <xsl:text>"     </xsl:text>
+                               <!-- Empty column for fixed subtitle lang here -->
+                               <xsl:text>      </xsl:text>
+                               <!-- Empty column for fixed subtitle here -->
+                       </xsl:when>
+                       <xsl:otherwise>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$source-subtitle-quoted" />
+                               <xsl:text>"     </xsl:text>
+                               <!-- Empty column for fixed subtitle lang here -->
+                               <xsl:text>      </xsl:text>
+                               <!-- Empty column for fixed subtitle here -->
+                       </xsl:otherwise>
+               </xsl:choose>
+               <xsl:text>&#10;</xsl:text>
+       </xsl:template>
+       
+       <!-- Autorité de personnes -->
+       <xsl:template match="/marc:collection/marc:record[substring(marc:leader, 7, 1) = 'z']" mode="person">
+               <xsl:variable name="bibliographic-leader" select="marc:controlfield[@tag='001']" />
+               <xsl:variable name="source-name">
+                       <xsl:choose>
+                               <xsl:when test="marc:datafield[@tag='100']">
+                                       <xsl:apply-templates select="marc:datafield[@tag='100']/marc:subfield[@code='a']" mode="person" />
+                               </xsl:when>
+                               <xsl:when test="marc:datafield[@tag='400']">
+                                       <xsl:apply-templates select="marc:datafield[@tag='400']/marc:subfield[@code='a']" mode="person" />
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <xsl:message terminate="yes">
+                                               <xsl:text xml:lang="fr">Aucun nom de personne n’a été trouvé pour la notice </xsl:text>
+                                               <xsl:value-of select="$bibliographic-leader" />
+                                               <xsl:text xml:lang="fr">.</xsl:text>
+                                       </xsl:message>
+                               </xsl:otherwise>
+                       </xsl:choose>
+               </xsl:variable>
+               <xsl:variable name="source-nickname">
+                       <xsl:if test="marc:datafield[@tag='500']/marc:subfield[@code='a']">
+                               <xsl:apply-templates select="marc:datafield[@tag='500']/marc:subfield[@code='a']" mode="person" />
+                       </xsl:if>
+               </xsl:variable>
+               
+               <xsl:variable name="fix-first-name">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-first-name', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-last-name">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-last-name', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-name-source">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-name-source', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-nickname">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-nickname', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               <xsl:variable name="fix-nickname-source">
+                       <xsl:for-each select="$strings-fix-doc">
+                               <xsl:value-of select="key('fix-record-nickname-source', $bibliographic-leader)" />
+                       </xsl:for-each>
+               </xsl:variable>
+               
+               <!-- Export name strings -->
+               <xsl:choose>
+                       <!-- If corresponding entry is found in fix document -->
+                       <xsl:when test="$fix-first-name != '' and $fix-last-name != '' and $fix-name-source = $source-name">
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$bibliographic-leader" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$source-name" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$fix-first-name" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$fix-last-name" />
+                               <xsl:text>"     </xsl:text>
+                       </xsl:when>
+                       <xsl:when test="$fix-first-name != '' and $fix-last-name != '' and $fix-name-source != $source-name">
+                               <xsl:message terminate="no">
+                                       <xsl:text>Un correctif pour la notice de l’entrée </xsl:text>
+                                       <xsl:value-of select="$bibliographic-leader" />
+                                       <xsl:text> existe, mais le nom dans la notice a été modifié depuis. La valeur de correction est ignorée.</xsl:text>
+                               </xsl:message>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$bibliographic-leader" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$source-name" />
+                               <xsl:text>"     </xsl:text>
+                               <!-- Empty column for fixed first name here -->
+                               <xsl:text>      </xsl:text>
+                               <!-- Empty column for fixed last name here -->
+                               <xsl:text>      </xsl:text>
+                       </xsl:when>
+                       <!-- No corresponding entry found in fix document -->
+                       <xsl:otherwise>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$bibliographic-leader" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$source-name" />
+                               <xsl:text>"     </xsl:text>
+                               <!-- Empty column for fixed first name here -->
+                               <xsl:text>      </xsl:text>
+                               <!-- Empty column for fixed last name here -->
+                               <xsl:text>      </xsl:text>
+                       </xsl:otherwise>
+               </xsl:choose>
+               
+               <!-- Export nickname strings -->
+               <xsl:choose>
+                       <!-- If corresponding entry is found in fix document -->
+                       <xsl:when test="$fix-nickname != '' and $fix-nickname-source = $source-nickname">
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$source-nickname" />
+                               <xsl:text>"     "</xsl:text>
+                               <xsl:value-of select="$fix-nickname" />
+                               <xsl:text>"</xsl:text>
+                       </xsl:when>
+                       <xsl:when test="$fix-nickname != '' and $fix-name-source != $source-name">
+                               <xsl:message terminate="no">
+                                       <xsl:text>Un correctif pour la notice de l’entrée </xsl:text>
+                                       <xsl:value-of select="$bibliographic-leader" />
+                                       <xsl:text> existe, mais le pseudonyme dans la notice a été modifié depuis. La valeur de correction est ignorée.</xsl:text>
+                               </xsl:message>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$source-nickname" />
+                               <xsl:text>"     "</xsl:text>
+                               <!-- Empty column for fixed nickname here -->
+                               <xsl:text>"</xsl:text>
+                       </xsl:when>
+                       <!-- No corresponding entry found in fix document -->
+                       <xsl:otherwise>
+                               <xsl:text>"</xsl:text>
+                               <xsl:value-of select="$source-nickname" />
+                               <xsl:text>"     "</xsl:text>
+                               <!-- Empty column for fixed nickname here -->
+                               <xsl:text>"</xsl:text>
+                       </xsl:otherwise>
+               </xsl:choose>
+               <xsl:text>&#10;</xsl:text>
+       </xsl:template>
+       
+       <!-- Corporate authority record -->
+       <xsl:template match="/marc:collection/marc:record[substring(marc:leader, 7, 1) = 'z' and marc:datafield[@tag='110']]" mode="corporate">
+               <xsl:variable name="bibliographic-leader" select="marc:controlfield[@tag='001']" />
+               <xsl:message terminate="yes">Pas encore implémenté</xsl:message>
+               
+               <!--<xsl:value-of select="$bibliographic-leader" />
+               <xsl:text>&#10;</xsl:text>
+               <xsl:message>Corporate</xsl:message>-->
+       </xsl:template>
+       
+       <!-- Meeting authority record -->
+       <xsl:template match="/marc:collection/marc:record[substring(marc:leader, 7, 1) = 'z' and marc:datafield[@tag='111']]" mode="meeting">
+               <xsl:variable name="bibliographic-leader" select="marc:controlfield[@tag='001']" />
+               <xsl:message terminate="yes">Pas encore implémenté</xsl:message>
+               
+               <!--<xsl:value-of select="$bibliographic-leader" />
+               <xsl:text>&#10;</xsl:text>
+               <xsl:message>Meeting</xsl:message>-->
+       </xsl:template>
+       
+       <!-- Title -->
+       <xsl:template match="marc:datafield[@tag='130'] | marc:datafield[@tag='245'] | marc:datafield[@tag='246'] | marc:datafield[@tag='740']" mode="title">
+               <xsl:variable name="b-position" select="count(marc:subfield[@code='b'][1]/preceding-sibling::*)+1" />
+               <xsl:value-of select="marc:subfield[@code='a']" />
+               <xsl:if test="marc:subfield[@code='n' and (position() &lt; $b-position or not(marc:subfield[@code='b']))]">
+                       <xsl:text> </xsl:text>
+                       <xsl:value-of select="marc:subfield[@code='n' and (position() &lt; $b-position or not(marc:subfield[@code='b']))]" />
+               </xsl:if>
+               <xsl:if test="marc:subfield[@code='p']">
+                       <xsl:text> </xsl:text>
+                       <xsl:value-of select="marc:subfield[@code='p']" />
+               </xsl:if>
+       </xsl:template>
+       
+       <!-- Subtitle -->
+       <xsl:template match="marc:datafield[@tag='245' and marc:subfield[@code='b']]" mode="subtitle">
+               <xsl:variable name="b-position" select="count(marc:subfield[@code='b'][1]/preceding-sibling::*)+1" />
+               <xsl:value-of select="marc:subfield[@code='b']" />
+               <xsl:value-of select="marc:subfield[@code='n' and position() &gt; $b-position]" />
+               <xsl:value-of select="marc:subfield[@code='p']" />
+       </xsl:template>
+       
+       <xsl:template name="string-replace-all">
+               <xsl:param name="text" />
+               <xsl:param name="replace" />
+               <xsl:param name="by" />
+               <xsl:choose>
+                       <xsl:when test="$text = '' or $replace = ''or not($replace)" >
+                               <xsl:value-of select="$text" />
+                       </xsl:when>
+                       <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>
+</xsl:stylesheet>