2010-06-18 22 views
68

Je ne connais pas vraiment XSL mais j'ai besoin de réparer ce code, je l'ai réduit pour le rendre plus simple.
Je reçois cette erreurXSLT chaîne remplacer

Invalid XSLT/XPath function

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 avec elle?

+0

Veuillez noter que la fonction 'replace()' est disponible à partir de XPath 2.0 (et par conséquent de XSLT 2.0) et prend en charge les remplacements d'expressions régulières. – Abel

Répondre

119

replace n'est pas disponible pour XSLT 1.0.

Codesling a un template for string-replace vous pouvez utiliser comme un substitut à 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ée comme:

<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 littéralement seulement besoin de remplacer un caractère par un autre, vous pouvez appeler translate qui a une signature similaire. Quelque chose comme cela fonctionne bien:

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

En outre, note, dans cet exemple, j'ai changé le nom de la variable « newText », dans les variables XSLT sont immuables, de sorte que vous ne pouvez pas faire l'équivalent de $foo = $foo comme vous eu dans votre code d'origine.

+0

Merci Mark, mais maintenant je reçois cette erreur: Une fonction d'extension XPath inconnue a été appelée – Aximili

+0

@aximili, désolé, a obtenu XSLT 1.0 et 2.0 confus, édité ... devrait être bon d'aller maintenant. –

+0

Je vois merci Mark! – Aximili

30

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

Ce modèle a les 3 paramètres comme ci-dessous

texte: - votre chaîne principale

remplacer: - la chaîne que vous souhaitez remplacer

par: - la chaîne qui répondra par nouvelle chaîne

Ci-dessous sont Modèle e

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

Ci-dessous exemple montre comment 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 consulter le below URL pour les détails.

+0

Utiliser xslt 1.0 Ce post/template a fonctionné pour moi alors que Mark Elliot ne l'a pas fait. – HostMyBus

11

Note: Si vous souhaitez utiliser le algo pour les cas déjà mentionné où vous avez besoin de remplacer grand nombre de cas dans la chaîne source (par exemple, nouvelles lignes long texte), il y a haute probabilité que vous » ll finira par StackOverflowException en raison de l'appel récursif.

Je résolu ce problème grâce à de Xalan (n'a pas regardé comment le faire dans saxon) intégré plongement de 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

Désolé si je suis bête mais je reçois: 'Impossible de trouver un script ou un objet d'extension associé à l'espace de noms 'xalan: // java.lang.String'.' –

+0

Quel est votre moteur XSLT? –

+0

Le Microsoft.NET j'ai peur ... –

5

Vous pouvez utiliser le code suivant lorsque votre processeur s'exécute sur .NET ou utilise MSXML (par opposition à Java ou d'autres processeurs natifs). Il utilise msxsl:script.

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

En outre, liez outlet à n'importe quel espace de noms que vous aimez, 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

Désolé si je suis bête, mais j'ai 'prefix outlet is not defined' ou' 'xsl: script' ne peut pas être un enfant de l'élément 'xsl: stylesheet' .' si je change msxsl pour mon préfixe. Je suppose que c'est une magie XSLT spécifique à Microsoft? –

+1

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

0

Le Rouine est assez bonne, mais il provoque mon application pour accrocher, donc je besoin d'ajouter le cas:

<xsl:when test="$text = '' or $replace = ''or not($replace)" > 
    <xsl:value-of select="$text" /> 
    <!-- Prevent thsi routine from hanging --> 
    </xsl:when> 

avant que la fonction est appelée récursive.

J'ai obtenu la réponse d'ici: When test hanging in an infinite loop

Merci!