2010-06-18 19 views
68

Realmente no conozco XSL pero tengo que corregir este código, lo he reducido para hacerlo más simple.
estoy recibiendo este errorReemplazo de cadena XSLT

Invalid XSLT/XPath function

en esta línea

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

Este es el 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> 

Puede alguien decirme lo que está mal con ella?

+0

Tenga en cuenta que la función 'replace()' está disponible desde XPath 2.0 (y por lo tanto XSLT 2.0) en adelante y admite reemplazos de expresiones regulares. – Abel

Respuesta

119

replace no está disponible para XSLT 1.0.

Codesling tiene una template for string-replace se puede utilizar como un sustituto de la función:

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

invocado como:

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

Por otro lado, si, literalmente, sólo se necesita reemplazar un carácter con otro, puede llamar al translate que tiene una firma similar. Algo como esto debería funcionar bien:

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

Además, nota, en este ejemplo, he cambiado el nombre de la variable a "newText", en las variables XSLT son inmutables, lo que no puede hacer el equivalente de $foo = $foo como si tenía en tu código original.

+0

Gracias Marcar, pero ahora recibo este error: Se llamó una función de extensión XPath desconocida – Aximili

+0

@aximili, lo siento, tengo XSLT 1.0 y 2.0 confundido, editado ... debería ser bueno ir ahora. –

+0

Veo gracias Mark! – Aximili

30

Aquí está la función XSLT que funcionará de forma similar a la función String.Replace() de C#.

Esta plantilla tiene los 3 parámetros de la siguiente manera

texto: - la cadena principal

reemplazar: - la cadena que desea reemplazar

por: - la cadena que responderá por una nueva cadena

Debajo están th e Plantilla

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

Debajo ejemplo muestra cómo llamarlo

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

También puede hacer referencia al below URL para los detalles.

+0

Usando xslt 1.0 Esta publicación/plantilla funcionó para mí, mientras que la de Mark Elliot no. – HostMyBus

11

Nota: En caso de que desee utilizar el algo ya mencionado para los casos en que es necesario reemplazar gran número de casos en la cadena de origen (por ejemplo, nuevas líneas de texto largo) hay alta probabilidad de que' terminará con StackOverflowException debido a la llamada recursiva.

I resuelto este problema gracias a Xalan 's (no se veía cómo hacerlo en Saxon) incorporado en Java Tipo de incrustación:

<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

Lo siento si estoy siendo tonto pero obtengo: 'No se puede encontrar un script o un objeto de extensión asociado con el espacio de nombres 'xalan: // java.lang.String'. –

+0

¿Cuál es su motor XSLT? –

+0

El de Microsoft.NET uno me temo ... –

5

Usted puede utilizar el código siguiente cuando su procesador se ejecuta en .NET o usa MSXML (a diferencia de los procesadores nativos basados ​​en Java u otros). Usa msxsl:script.

Asegúrese de agregar el espacio de nombres xmlns:msxsl="urn:schemas-microsoft-com:xslt" a su elemento raíz xsl:stylesheet o xsl:transform.

Además, enlace outlet a cualquier espacio de nombres que desee, por ejemplo 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

Lo siento si estoy siendo tonto, pero obtengo 'prefix outlet is not defined' o''xsl: script 'no puede ser un elemento secundario del elemento' xsl: stylesheet '. Si cambio msxsl por mi prefijo. Supongo que esta es una magia XSLT específica de Microsoft. –

+1

@IanGrainger, no es 'xsl: script', sino' msxsl: script', y tiene un espacio de nombres diferente (he actualizado la respuesta de John). – Abel

0

El Rouine es bastante bueno, sin embargo, hace que mi aplicación para colgar, así que tenía que añadir el caso:

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

antes de la función se llama de forma recursiva.

Tengo la respuesta desde aquí: When test hanging in an infinite loop

Gracias!

Cuestiones relacionadas