XSL Функция множественного поиска и замены - PullRequest
4 голосов
/ 12 марта 2011

Я пытаюсь использовать функцию XSL translate () для создания чего-то вроде функции поиска и замены следующим образом:

<xsl:template name="create-id">
    <xsl:param name="id" />
    <xsl:call-template name="search-and-replace">
        <xsl:with-param name="str" select="$id" />
        <xsl:with-param name="search">0123456789</xsl:with-param>
        <xsl:with-param name="replace">abcdefghij</xsl:with-param>
    </xsl:call-template>
</xsl:template>

<xsl:template name="search-and-replace">
    <xsl:param name="str" />
    <xsl:param name="search" />
    <xsl:param name="replace" />
    <xsl:variable name="newstr" select="translate($str, $search,
    $replace)" />
    <xsl:choose>
        <xsl:when test="contains($newstr, $search)">
            <xsl:call-template name="search-and-replace">
                <xsl:with-param name="str" select="$newstr" />
                <xsl:with-param name="search" select="$search" />
                <xsl:with-param name="replace" select="$replace" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$newstr" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Однако в моей логике что-то не так, так как кажется, что она удаляет последний символ в возвращаемой строке. Я предполагаю, что translate () заменяет только первый экземпляр каждого символа в строке и не является действительно рекурсивным.

Буду признателен за любые мысли или пожелания.

Ответы [ 4 ]

8 голосов
/ 12 марта 2011

Функция translate() может заменить только один символ другим одним символом (или пустым символом (удалить)).Таким образом, он не может решить проблему замены строки.

Вот полное решение XSLT 1.0 для задачи множественной замены :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <my:params xml:space="preserve">
        <pattern>
            <old>&#xA;</old>
            <new><br/></new>
        </pattern>
        <pattern>
            <old>quick</old>
            <new>slow</new>
        </pattern>
        <pattern>
            <old>fox</old>
            <new>elephant</new>
        </pattern>
        <pattern>
            <old>brown</old>
            <new>white</new>
        </pattern>
    </my:params>

    <xsl:variable name="vPats"
         select="document('')/*/my:params/*"/>

    <xsl:template match="text()" name="multiReplace">
        <xsl:param name="pText" select="."/>
        <xsl:param name="pPatterns" select="$vPats"/>

        <xsl:if test="string-length($pText) >0">
            <xsl:variable name="vPat" select=
            "$vPats[starts-with($pText, old)][1]"/>

            <xsl:choose>
                <xsl:when test="not($vPat)">
                    <xsl:copy-of select="substring($pText,1,1)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$vPat/new/node()"/>
                </xsl:otherwise>
            </xsl:choose>

            <xsl:call-template name="multiReplace">
                <xsl:with-param name="pText" select=
                "substring($pText, 1 + not($vPat) + string-length($vPat/old/node()))"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

, когда этопреобразование применяется к следующему XML-документу:

<t>The quick
brown fox</t>

желаемый, правильный результат получается :

The slow<br />white elephant

Объяснение :

  1. Используется именованный шаблон, который вызывает себя рекурсивно.

  2. Все пары множественных замен -> пары замены предоставляются в одномвнешний параметр, который для удобства здесь указывается inline как элемент глобального уровня <my:params>.

  3. Рекурсия принимает каждый отдельный символ в исходной строке (слева направо) и находитпервый шаблон, который начинается с этого символа в этой позиции в строке.

  4. Замена может быть не только строкой, но и любым узлом.В этом конкретном случае мы заменяем каждый символ NL элементом <br/>.

3 голосов
/ 12 марта 2011

Определение функции translate($arg, $mapString, $transString):

Возвращает значение $arg, измененное так, что каждый символ в значении $arg, который встречается в некоторой позиции N в значениииз $mapString был заменен символом, который находится в позиции N в значении $transString.

То есть он не заменяет подстроку другой строкой, а отображает символы вдругие персонажи.Для замены подстроки используйте что-то вроде

<xsl:template name="search-and-replace">
  <xsl:param name="str"/>
  <xsl:param name="search"/>
  <xsl:param name="replace"/>
  <xsl:choose>
    <xsl:when test="contains($str, $search)">
      <xsl:value-of select="substring-before($str, $search)"/>
      <xsl:value-of select="$replace"/>
      <xsl:call-template name="search-and-replace">
        <xsl:with-param name="str" select="substring-after($str, $search)"/>
        <xsl:with-param name="search" select="$search"/>
        <xsl:with-param name="replace" select="$replace"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$str"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
0 голосов
/ 12 марта 2011

str: заменить с exslt .Он делает именно то, что вы хотите, и уже написан и тестируется некоторыми гуру xslt.Источник xslt также доступен там .

0 голосов
/ 12 марта 2011

Похоже, что вы никогда не будете правдой, поскольку вы уже заменили все символы в $ search на $ replace в

<xsl:variable name="newstr" select="translate($str, $search,
    $replace)" />

заранее.

...