2015-01-26 7 views
0

Я преобразовываю индексную строку в индексные маркеры. Строка может содержать несколько уровней, разделенных двоеточиями. Каждая секция может также иметь некоторые другие специальные символы, которые необходимо обработать позже.Почему мой вызов-шаблон зацикливается навсегда?

Моя тестовая строка «Главная: Изменить», которые должны быть преобразованы в:

<indexterm>Home<indexterm>Change</indexterm></indexterm> 

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

<xsl:template name="parseindexstring"> 
    <xsl:param name="string"/> 
    <xsl:choose> 
     <xsl:when test="contains(.,':')"> 
      <xsl:value-of select="substring-before(.,':')"/> 
      <indexterm> 
       <xsl:value-of select="substring-after(.,':')"/> 
      </indexterm> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="."/> 
     </xsl:otherwise> 
    </xsl:choose>  
</xsl:template> 

Но я не хочу, чтобы ограничить обработку только один уровень, я решил использовать рекурсию вместо:

<xsl:template name="parseindexstring"> 
    <xsl:param name="string"/> 
    <xsl:choose> 
     <xsl:when test="contains(.,':')"> 
      <xsl:value-of select="substring-before(.,':')"/> 
      <indexterm> 
       <xsl:call-template name="parseindexstring"> 
        <xsl:with-param name="string" select="substring-after(.,':')"/> 
       </xsl:call-template> 
      </indexterm> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="."/> 
     </xsl:otherwise> 
    </xsl:choose>  
</xsl:template> 

Это бежит в бесконечный цикл, даже на индексной строке, которая имеет только два уровня (т. Е. Только один двоеточие), и я не могу понять, почему. Я передаю вторую часть строки вложенный шаблон вызова, но похоже, что он всегда принимает строковый параметр вызова верхнего уровня. По крайней мере, это то, на что похоже, если я один шаг XSL в моем отладчике. Что я забываю или недопонимаю здесь?

ответ

1

Проблема в том, что вы не используете параметр string в шаблоне, но используете оператор ., который ссылается на текущий контекст (который я угадываю, это элемент, содержащий вашу строку ввода). Поскольку текущий контекст не изменяется, выражение contains(.,':') всегда будет истинным, а шаблон просто обрабатывает один и тот же контекст снова и снова, независимо от того, для чего установлено значение string.

Попробуйте этот шаблон вместо:

<xsl:template name="parseindexstring"> 
    <xsl:param name="string"/> 
    <xsl:choose> 
     <xsl:when test="contains($string,':')"> 
      <xsl:value-of select="substring-before($string,':')"/> 
      <indexterm> 
       <xsl:call-template name="parseindexstring"> 
        <xsl:with-param name="string" select="substring-after($string,':')"/> 
       </xsl:call-template> 
      </indexterm> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$string"/> 
     </xsl:otherwise> 
    </xsl:choose>  
</xsl:template> 
+0

Да. Это работает. Если я правильно ее понимаю, шаблон соответствия изменяет контекст на все, что помечено как выбор, который нужно обработать, а шаблон вызова не изменяет контекст. Теперь это имеет смысл для меня. Большое спасибо за помощь. – 4everJang

Смежные вопросы