XSLT文字列置換


86

私はXSLを本当に知りませんが、このコードを修正する必要があります。簡単にするためにコードを減らしました。
このエラーが発生します

無効なXSLT / XPath関数

この行に

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

これは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>

誰かがそれの何が問題なのか教えてもらえますか?


このreplace()関数はXPath2.0(したがって、XSLT 2.0)以降で使用可能であり、正規表現の置換をサポートしていることに注意してください。
アベル

回答:


150

replace XSLT1.0では使用できません。

Codeslingには、関数の代わりに使用できる文字列置換のテンプレートがあります。

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

として呼び出されます:

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

一方、文字通り1つの文字を別の文字に置き換えるだけでよい場合translateは、同様の署名を持つ呼び出しを行うことができます。このようなものはうまくいくはずです:

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

また、この例では、変数名を「newtext」に変更しました。XSLT変数は不変であるため$foo = $foo、元のコードと同じことはできません。


Markに感謝しますが、次のエラーが発生します。不明なXPath拡張関数が呼び出されました
Aximili 2010年

@aximili、申し訳ありませんが、XSLT 1.0と2.0が混乱し、編集されました...今すぐ行ってください。
マークエリオット2010年

19
この答えは間違っています!XSLTのreplace関数は、文字列全体ではなく、対応するSINGLECHARACTERSを置き換えます。たとえば、ここを参照してください:w3schools.com/xpath/xpath_functions.asp
Jakub

12
@Jakubあなたが考えているのはtranslate、ではなくreplacereplaceXPath 2.0の関数は、2番目の引数を正規表現として扱い、その式のすべての一致を指定された置換文字列($n正規表現内のキャプチャグループへの参照を含む場合があります)に置き換えます。translate(1.0および2.0での)関数は、単一文字-ため、単一文字の置き換えを行うものです。
イアンロバーツ

6
使用例の4行目<xsl:with-param name="replace" select="'a'" />は、aを引用符で囲んではいけません か?
DJL 2013

37

これは、C#のString.Replace()関数と同様に機能するXSLT関数です。

このテンプレートには、以下の3つのパラメータがあります

テキスト:-メインの文字列

置換:-置換する文字列

by:-新しい文字列で応答する文字列

以下はテンプレートです

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

以下のサンプルは、それを呼び出す方法を示しています

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

詳しくは下記URLをご覧ください。


1
xslt 1.0の使用この投稿/テンプレートは機能しましたが、MarkElliotは機能しませんでした。
hostMyBus 2016

12

注:ソース文字列内の膨大な数のインスタンス(長いテキストの新しい行など)を置き換える必要がある場合に前述のアルゴリズムを使用する場合は、再帰的であるために終了する可能性が高くなりますStackOverflowExceptionコール。

XalanSaxonでそれを行う方法を調べていませんでした)の組み込み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>

申し訳ありませんが、私は馬鹿であることだが、私は取得する場合:Cannot find a script or an extension object associated with namespace 'xalan://java.lang.String'.
イアン・グレインジャー

XSLTエンジンは何ですか?
ミラン・アレクシッチ2014

3
私のコメントは、利用可能なJavaクラスパス内の利用可能なタイプへの直接マッピングをサポートする最も人気のあるJava XSLT 1.0エンジンXalan(xml.apache.org/xalan-j)に対するものでした。あなたは、.NETスタックのための私の解決策を適用することはできません
ミラン・アレックジック

@ IanGrainger、<msxsl:script>.NETメソッド、ライブラリなどを呼び出すことができるブロックを追加することで、.NETで使用できます。.NETはEXSLT拡張関数もサポートしているため、必要ありません。
アベル

EXSLTはまたでサポートされてlibxsltは、したがって、すべての子孫にxsltprocの等...
アランPannetier

7

プロセッサが.NETで実行されている場合、またはMSXMLを使用している場合(Javaベースまたは他のネイティブプロセッサとは対照的に)、次のコードを使用できます。を使用しmsxsl:scriptます。

必ず名前空間xmlns:msxsl="urn:schemas-microsoft-com:xslt"をルートxsl:stylesheetまたはxsl:transform要素に追加してください。

さらに、outletたとえば、任意の名前空間にバインドします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')" />

ばかげている場合は申し訳ありませんが、プレフィックスのmsxslを取得しprefix outlet is not definedたり'xsl:script' cannot be a child of the 'xsl:stylesheet' element.、変更したりします。これはMicrosoft固有のXSLTの魔法だと思いますか?
Ian Grainger 2014

1
@IanGrainger、ではありませんxsl:scriptmsxsl:script、名前空間が異なります(Johnの回答を更新しました)。
アベル

1

私はこの答えを打ち続けます。しかし、それらのどれもxsltproc(そしておそらくほとんどのXSLT 1.0プロセッサ)の最も簡単な解決策をリストしていません:

  1. exslt文字列名をスタイルシートに追加します。
<xsl:stylesheet
  version="1.0"
  xmlns:str="http://exslt.org/strings"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  1. 次に、次のように使用します。
<xsl:value-of select="str:replace(., ' ', '')"/>

1
私のコンピューター(macOS 10.13)のxsltprocはこのstr:replace()機能をサポートしていません。他の主要なXSLT1.0プロセッサ(Xalan、Saxon 6.5、Microsoft)も同様です。
michael.hor257k

0

ルーチンはかなり良いですが、アプリがハングする原因になるため、ケースを追加する必要がありました。

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

関数が再帰的に呼び出される前。

私はここから答えを得ました: 無限ループにぶら下がっているテストのとき

ありがとうございました!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.