XSLT-Zeichenfolge ersetzen

84

Ich kenne XSL nicht wirklich, aber ich muss diesen Code korrigieren. Ich habe ihn reduziert, um ihn einfacher zu machen.
Ich erhalte diesen Fehler

Ungültige XSLT / XPath-Funktion

in dieser Zeile

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

Dies ist die 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>

Kann mir jemand sagen, was daran falsch ist?

Aximili
quelle
Bitte beachten Sie, dass die replace()Funktion ab XPath 2.0 (und damit XSLT 2.0) verfügbar ist und das Ersetzen regulärer Ausdrücke unterstützt.
Abel

Antworten:

146

replace ist für XSLT 1.0 nicht verfügbar.

Codesling verfügt über eine Vorlage zum Ersetzen von Zeichenfolgen, die Sie als Ersatz für die Funktion verwenden können:

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

aufgerufen als:

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

Wenn Sie dagegen buchstäblich nur ein Zeichen durch ein anderes ersetzen müssen, können Sie anrufen, translatedas eine ähnliche Signatur hat. So etwas sollte gut funktionieren:

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

Beachten Sie außerdem, dass ich in diesem Beispiel den Variablennamen in "newtext" geändert habe. In XSLT sind Variablen unveränderlich, sodass Sie nicht das Gleiche tun können, $foo = $foowie Sie es in Ihrem ursprünglichen Code getan haben .

Mark Elliot
quelle
Danke Mark, aber jetzt
bekomme
@aximili, sorry, habe XSLT 1.0 und 2.0 verwirrt, bearbeitet ... sollte jetzt gut gehen.
Mark Elliot
19
Diese Antwort ist falsch! Die Ersetzungsfunktion in XSLT ersetzt die entsprechenden EINZELNEN ZEICHEN, nicht die gesamten Zeichenfolgen! Siehe zum Beispiel hier: w3schools.com/xpath/xpath_functions.asp
Jakub
12
@ Jakub Du denkst translatenicht daran replace. Die replaceFunktion in XPath 2.0 behandelt ihr zweites Argument als regulären Ausdruck und ersetzt alle Übereinstimmungen dieses Ausdrucks durch die angegebene Ersetzungszeichenfolge (die möglicherweise $nVerweise auf die Erfassung von Gruppen im regulären Ausdruck enthält ). Die translateFunktion (in 1.0 und 2.0) ersetzt Einzelzeichen für Einzelzeichen.
Ian Roberts
6
Sollte die 4. Zeile in der Beispielverwendung nicht <xsl:with-param name="replace" select="'a'" />mit Anführungszeichen um das a stehen?
DJL
36

Hier ist die XSLT-Funktion, die ähnlich wie die String.Replace () -Funktion von C # funktioniert.

Diese Vorlage hat die folgenden 3 Parameter

Text : - Ihre Hauptzeichenfolge

Ersetzen : - Die Zeichenfolge, die Sie ersetzen möchten

von : - der Zeichenfolge, die mit einer neuen Zeichenfolge antwortet

Unten ist die Vorlage

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

Das folgende Beispiel zeigt, wie man es aufruft

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

Sie können auch die folgende URL für die Details verweisen .

Optimus
quelle
1
Verwenden von xslt 1.0 Dieser Beitrag / diese Vorlage hat bei mir funktioniert, Mark Elliots jedoch nicht.
HostMyBus
12

Hinweis: Wenn Sie das bereits erwähnte Algo für Fälle verwenden möchten, in denen Sie eine große Anzahl von Instanzen in der Quellzeichenfolge ersetzen müssen (z. B. neue Zeilen im Langtext), besteht eine hohe Wahrscheinlichkeit, dass Sie StackOverflowExceptionaufgrund der Rekursion enden Anruf.

Ich habe dieses Problem dank der in Java eingebauten Java-Typ-Einbettung von Xalan behoben (ich habe nicht nachgesehen, wie man es auf Sächsisch macht ):

<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>
Milan Aleksić
quelle
Tut mir leid, wenn ich dumm bin, aber ich bekomme:Cannot find a script or an extension object associated with namespace 'xalan://java.lang.String'.
Ian Grainger
Was ist Ihre XSLT-Engine?
Milan Aleksić
3
Mein Kommentar war für die beliebteste Java XSLT 1.0-Engine Xalan ( xml.apache.org/xalan-j ), die die direkte Zuordnung zu verfügbaren Typen innerhalb des verfügbaren Java-Klassenpfads unterstützt. Sie können meine Lösung für .Net Stack nicht anwenden
Milan Aleksić
@IanGrainger, Sie können es mit .NET verwenden, indem Sie einen <msxsl:script>Block hinzufügen , der jede .NET-Methode, -Bibliothek usw. aufrufen kann. Obwohl .NET auch die EXSLT-Erweiterungsfunktionen unterstützt, müssen Sie dies nicht tun.
Abel
exslt wird auch in libxslt und damit in allen Nachkommen xsltproc usw. unterstützt ...
Alain Pannetier
7

Sie können den folgenden Code verwenden, wenn Ihr Prozessor unter .NET ausgeführt wird oder MSXML verwendet (im Gegensatz zu Java-basierten oder anderen nativen Prozessoren). Es verwendet msxsl:script.

Stellen Sie sicher, dass Sie den Namespace xmlns:msxsl="urn:schemas-microsoft-com:xslt"zu Ihrem Stamm xsl:stylesheetoder xsl:transformElement hinzufügen .

Binden Sie außerdem beispielsweise outletan einen beliebigen Namespace 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')" />
John Jin
quelle
Tut mir leid, wenn ich dumm bin, aber ich bekomme prefix outlet is not definedoder 'xsl:script' cannot be a child of the 'xsl:stylesheet' element.wenn ich msxsl für mein Präfix ändere. Ich vermute, dies ist eine Microsoft-spezifische XSLT-Magie?
Ian Grainger
1
@ IanGrainger ist es nicht xsl:script, aber msxsl:script, und es hat einen anderen Namespace (ich habe Johns Antwort aktualisiert).
Abel
1

Ich treffe diese Antwort immer wieder. Aber keiner von ihnen listet die einfachste Lösung für xsltproc (und wahrscheinlich die meisten XSLT 1.0-Prozessoren) auf:

  1. Fügen Sie dem Stylesheet den Namen der exslt-Zeichenfolgen hinzu, dh:
<xsl:stylesheet
  version="1.0"
  xmlns:str="http://exslt.org/strings"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  1. Dann benutze es wie folgt:
<xsl:value-of select="str:replace(., ' ', '')"/>
Berend de Boer
quelle
1
Das xsltproc auf meinem Computer (macOS 10.13) unterstützt die str:replace()Funktion NICHT . Keiner der anderen großen XSLT 1.0-Prozessoren - Xalan, Saxon 6.5 und Microsoft.
michael.hor257k
0

Die Rouine ist ziemlich gut, aber meine App bleibt hängen, daher musste ich den Fall hinzufügen:

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

bevor die Funktion rekursiv aufgerufen wird.

Ich habe die Antwort von hier bekommen: Beim Test hängen in einer Endlosschleife

Danke dir!

Chesare
quelle