93 votes

Remplacement de chaîne XSLT

Je ne connais pas vraiment XSL mais j'ai besoin de corriger ce code, je l'ai réduit pour le rendre plus simple.
J'obtiens cette erreur

Fonction XSLT/XPath non valide

sur cette ligne

<xsl:variable name="text" select="replace($text,'a','b')"/>

C'est le XSL

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:inm="http://www.inmagic.com/webpublisher/query" version="1.0">
    <xsl:output method="text" encoding="UTF-8" />

    <xsl:preserve-space elements="*" />
    <xsl:template match="text()" />

    <xsl:template match="mos">
        <xsl:apply-templates />

        <xsl:for-each select="mosObj">
          'Notes or subject' 
           <xsl:call-template
                name="rem-html">
                <xsl:with-param name="text" select="SBS_ABSTRACT" />
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="rem-html">
        <xsl:param name="text" />
        <xsl:variable name="text" select="replace($text, 'a', 'b')" />
    </xsl:template>
</xsl:stylesheet>

Quelqu'un peut-il me dire ce qui ne va pas ?

0 votes

Veuillez noter que le replace() est disponible à partir de XPath 2.0 (et donc XSLT 2.0) et prend en charge les remplacements d'expressions régulières.

160voto

Mark Elliot Points 31871

replace n'est pas disponible pour XSLT 1.0.

Codesling a un modèle pour le remplacement de chaînes de caractères que vous pouvez utiliser comme substitut de la fonction :

<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)" >
            <!-- Prevent this routine from hanging -->
            <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>

invoqué en tant que :

<xsl:variable name="newtext">
    <xsl:call-template name="string-replace-all">
        <xsl:with-param name="text" select="$text" />
        <xsl:with-param name="replace" select="a" />
        <xsl:with-param name="by" select="b" />
    </xsl:call-template>
</xsl:variable>

D'autre part, si vous n'avez littéralement besoin que de remplacer un caractère par un autre, vous pouvez appeler translate qui a une signature similaire. Quelque chose comme ça devrait fonctionner :

<xsl:variable name="newtext" select="translate($text,'a','b')"/>

Notez également que, dans cet exemple, j'ai changé le nom de la variable en "newtext", en XSLT les variables sont immuables, donc vous ne pouvez pas faire l'équivalent de $foo = $foo comme vous l'aviez dans votre code original.

0 votes

Merci Mark, mais maintenant j'obtiens cette erreur : Une fonction d'extension XPath inconnue a été appelée

0 votes

@aximili, désolé, j'ai confondu XSLT 1.0 et 2.0, j'ai édité... ça devrait être bon maintenant.

19 votes

Cette réponse est fausse ! La fonction replace de XSLT remplace les CARACTÈRES UNIQUES correspondants, pas les chaînes entières ! Voir par exemple ici : w3schools.com/xpath/xpath_functions.asp

41voto

Dilip Nikam Points 316

Voici la fonction XSLT qui fonctionnera de manière similaire à la fonction String.Replace() de C#.

Ce modèle comporte les 3 paramètres suivants

texte :- votre corde principale

remplacer :- la chaîne de caractères que vous voulez remplacer

par :- la chaîne qui sera répondue par la nouvelle chaîne

Vous trouverez ci-dessous le modèle

<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>

L'exemple ci-dessous montre comment l'appeler

<xsl:variable name="myVariable ">
  <xsl:call-template name="string-replace-all">
    <xsl:with-param name="text" select="'This is a {old} text'" />
    <xsl:with-param name="replace" select="'{old}'" />
    <xsl:with-param name="by" select="'New'" />
  </xsl:call-template>
</xsl:variable>

Vous pouvez également vous référer à la sous l'URL pour les détails.

2 votes

Utilisation de xslt 1.0 Ce post/modèle a fonctionné pour moi, mais pas celui de Mark Elliot.

14voto

Milan Aleksic Points 869

Note : Si vous souhaitez utiliser l'algo déjà mentionné pour les cas où vous devez remplacer un grand nombre d'instances dans la chaîne de caractères source (par exemple, de nouvelles lignes dans un long texte), il y a haut probabilité que vous vous retrouviez avec StackOverflowException à cause de l'appel récursif.

J'ai résolu ce problème grâce à Xalan (je n'ai pas cherché à savoir comment le faire en Saxon ) intégré dans le type Java :

<xsl:stylesheet version="1.0" exclude-result-prefixes="xalan str"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xalan="http://xml.apache.org/xalan"
                xmlns:str="xalan://java.lang.String"
        >
...
<xsl:value-of select="str:replaceAll(
    str:new(text()),
    $search_string,
    $replace_string)"/>
...
</xsl:stylesheet>

0 votes

Désolé si je suis stupide mais je comprends : Cannot find a script or an extension object associated with namespace 'xalan://java.lang.String'.

0 votes

Quel est votre moteur XSLT ?

3 votes

Mon commentaire concernait le moteur Java XSLT 1.0 le plus populaire, Xalan ( xml.apache.org/xalan-j ), qui prend en charge le mappage direct des types disponibles dans le classpath Java ; vous ne pouvez pas appliquer ma solution pour la pile .Net.

9voto

Berend de Boer Points 320

Je n'arrête pas de tomber sur cette réponse. Mais aucune d'entre elles n'indique la solution la plus simple pour xsltproc (et probablement la plupart des processeurs XSLT 1.0) :

  1. Ajouter le nom des chaînes exslt à la feuille de style, c'est-à-dire :

    <xsl:stylesheet version="1.0" xmlns:str="http://exslt.org/strings" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  2. Alors utilise-le comme ça :

    <xsl:value-of select="str:replace(., ' ', '')"/>

7voto

John Jin Points 31

Vous pouvez utiliser le code suivant lorsque votre processeur fonctionne sur .NET Framework (Non supporté sur .NET Core ou .NET 5) ou utilise MSXML (par opposition aux processeurs basés sur Java ou à d'autres processeurs natifs). Il utilise msxsl:script .

Assurez-vous d'ajouter l'espace de nom xmlns:msxsl="urn:schemas-microsoft-com:xslt" à votre racine xsl:stylesheet o xsl:transform élément.

En outre, lier outlet à l'espace de nom de votre choix, par exemple xmlns:outlet = "http://my.functions" .

<msxsl:script implements-prefix="outlet" language="javascript">
function replace_str(str_text,str_replace,str_by)
{
     return str_text.replace(str_replace,str_by);
}
</msxsl:script>

<xsl:variable name="newtext" select="outlet:replace_str(string(@oldstring),'me','you')" />

0 votes

Désolé si je suis stupide, mais j'ai obtenu prefix outlet is not defined o 'xsl:script' cannot be a child of the 'xsl:stylesheet' element. si je change le msxsl pour mon préfixe. Je suppose qu'il s'agit d'une magie XSLT spécifique à Microsoft ?

1 votes

@IanGrainger, ce n'est pas le cas. xsl:script pero msxsl:script et il a un espace de nom différent (j'ai mis à jour la réponse de John).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X