Ошибка в xslt или xml при запуске кода XSL для факториала - PullRequest
2 голосов
/ 18 декабря 2010

У меня есть пример для факториала данного числа в xml, используя xsl. Мой код XML: fact.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="fact.xsl"?>
<numbers>
<number> 5
</number>
</numbers>

и мой XSL-код fact.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:apply-templates>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template name="factorial">
        <xsl:param name="number" select="$number"/>
        <xsl:param name="result" select="1"/>
        <xsl:if test="$number &gt; 1">
            <xsl:call-template name="factorial"> 
                <xsl:with-param name="number" select="$number - 1"/>
                <xsl:with-param name="result">
                    <xsl:value-of select="$number * $result"/>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:if>   
        <xsl:if test="$number = 1">
            <xsl:value-of select= "$result"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Но, когда я запускаю этот fact.xml, вывод факториала показывает только 5 вместо 120.

Так в чем же ошибка в коде, в XML или XSL?

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 18 декабря 2010

В предоставленном коде есть / было несколько ошибок , и совместимый процессор XSLT должен их вызывать и не давать никакого результата. Некоторые / все эти ошибки могут больше не отображаться, поскольку ОП тем временем редактировал свой код ...).

<xsl:apply-templates match="factorial">

Инструкция <xsl:apply-templates> не имеет атрибута соответствия - здесь возникает ошибка.

<xsl:param name="number" select="$number"/>

Это вызывает ошибку, поскольку $number не определен в данный момент и не может использоваться при указании значения по умолчанию для параметра $number.

Более важной ошибкой является то, что именованный шаблон factorial никогда не вызывается.

Вот исправленный код :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="number[. > 1]" name="factorial">
   <xsl:param name="pNumber" select="."/>
   <xsl:param name="pResult" select="1"/>

   <xsl:choose>
       <xsl:when test="$pNumber > 1">
         <xsl:call-template name="factorial">
           <xsl:with-param name="pNumber"
                select="$pNumber -1"/>
           <xsl:with-param name="pResult"
                select="$pNumber * $pResult"/>
         </xsl:call-template>
        </xsl:when>
        <xsl:when test="$pNumber = 1">
          <xsl:value-of select= "$pResult"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:message terminate="yes">Error</xsl:message>
        </xsl:otherwise>
    </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

при применении в предоставленном XML-документе :

<numbers>
    <number> 5 </number>
</numbers>

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

120
1 голос
/ 18 декабря 2010

Ваш первый шаблон соответствует узлу numbers, но ничего не делает.

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

Поэтому вывод равен 5.


Посмотрим, что произойдет.В XSLT шаблоны можно вызывать двумя способами.

  • Во-первых, они могут соответствовать элементу входных данных XML.Ваш первый шаблон делает именно это: в вашем исходном вопросе он соответствует /numbers node;в вашей ревизии он соответствует любому корневому элементу (что в данном случае одно и то же).
  • Во-вторых, их можно вызывать из шаблона через call-template.Это то, что вы делаете во втором шаблоне, рекурсивно вызывая себя.

Проблема в том, что второй шаблон вызывается только из ... угадайте ... самого второго шаблона.Поэтому, поскольку он никогда не вызывается, он никогда не будет выполнен.

Теперь мы добавим вызов к этому шаблону извне, а точнее из первого шаблона.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="numbers">
    <output>
      <!-- Here's a missing call to the second template -->
      <xsl:call-template name="factorial">
        <xsl:with-param name="number" select="number"/>
        <xsl:with-param name="result" select="1"/>
      </xsl:call-template>
    </output>
  </xsl:template>
  <xsl:template name="factorial">
    <xsl:param name="number" />
    <xsl:param name="result" />
    <intermediary number="{$number}">
      <xsl:value-of select="$result"/>
    </intermediary>
    <xsl:if test="$number &gt; 1">
      <xsl:call-template name="factorial">
        <xsl:with-param name="number" select="$number - 1"/>
        <xsl:with-param name="result" select="$number * $result"/>
      </xsl:call-template>
    </xsl:if>
    <xsl:if test="$number = 1">
      <result>
        <xsl:value-of select="$result"/>
      </result>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

Мы такжеМы хотим быть уверены, что шаблон работает правильно, поэтому мы выводим промежуточные состояния.

<?xml version="1.0" encoding="utf-8"?>
<output>
  <intermediary number="&#xA;    5&#xA;  ">1</intermediary>
  <intermediary number="4">5</intermediary>
  <intermediary number="3">20</intermediary>
  <intermediary number="2">60</intermediary>
  <intermediary number="1">120</intermediary>
  <result>120</result>
</output>

Окончательный результат верен, но первое промежуточное состояние все еще странно.Он показывает, что число 5 обрабатывалось как строка с пробелом в начале и в конце.

Чтобы избавиться от этого, элемент innerXML number должен быть преобразован в действительное число.Для этого вы можете использовать метод number():

<xsl:call-template name="factorial">
  <xsl:with-param name="number" select="number(number)"/>
  <xsl:with-param name="result" select="1"/>
</xsl:call-template>

Теперь вывод корректен от начала до конца, а промежуточный вывод можно удалить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...