Рекурсивно применять шаблоны к результирующему дереву в XSLT (постоянное свертывание)

Я пытаюсь применить константное свертывание к представлениям XML простых числовых выражений. Свертывание констант - это процесс замены константных (под) выражений их буквальным значением. Часть постоянного свертывания заменяет каждую двоичную операцию, которая применяется к двум литеральным значениям, на вычисляемый литеральный результат. Так скажем, у нас есть выражение:

1+x+2*(3+1)

и его представление XML:

<addition>
   <addition>
      <value>1</value>
      <variable>x</variable>
   </addition>
   <multiplication>
      <value>2</value>
      <addition>
         <value>3</value>
         <value>1</value>
      </addition>
   </multiplication>
</addition>

мы можем заменить

<addition>
   <value>3</value>
   <value>1</value>
</addition>

с

<value>4</value>

И впоследствии мы можем заменить

<multiplication>
   <value>2</value>
   <value>4</value>
</multiplication>

с

<value>8</value>

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

<addition>
   <addition>
      <value>1</value>
      <variable>x</variable>
   </addition>
   <value>8</value>
</addition>

Часть моей таблицы стилей XSLT выглядит так:

<xsl:template match="addition[count(value) = 2]">
   <value>
      <xsl:value-of select="value[1] + value[2]" />
   </value>
</xsl:template>

<xsl:template match="multiplication[count(value) = 2]">
   <value>
      <xsl:value-of select="value[1] * value[2]" />
   </value>
</xsl:template>

...

<xsl:template match="@*|node()">
   <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
   </xsl:copy>
</xsl:template>

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

Однако эта таблица стилей будет применять константное свертывание только один раз, заменяя только самые глубокие элементы бинарных операций их литеральными значениями. Единственный способ заставить эту таблицу стилей работать - продолжать преобразовывать выходные данные последнего преобразования, пока входной и выходной документы не совпадут. Я новичок в XSLT, так что я уверен, что должен быть более естественный способ сделать это.

1 ответ

Решение

Это преобразование:

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

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="addition[not(descendant::variable)]">
     <xsl:variable name="vArg1">
       <xsl:apply-templates select="*[1]"/>
     </xsl:variable>
     <xsl:variable name="vArg2">
       <xsl:apply-templates select="*[2]"/>
     </xsl:variable>

     <value>
       <xsl:value-of select="$vArg1 + $vArg2"/>
  </value>
 </xsl:template>

 <xsl:template match="multiplication[not(descendant::variable)]">
     <xsl:variable name="vArg1">
       <xsl:apply-templates select="*[1]"/>
     </xsl:variable>
     <xsl:variable name="vArg2">
       <xsl:apply-templates select="*[2]"/>
     </xsl:variable>

     <value>
       <xsl:value-of select="$vArg1 * $vArg2"/>
  </value>
 </xsl:template>
</xsl:stylesheet>

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

<addition>
   <addition>
      <value>1</value>
      <variable>x</variable>
   </addition>
   <multiplication>
      <value>2</value>
      <addition>
         <value>3</value>
         <value>1</value>
      </addition>
   </multiplication>
</addition>

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

<addition>
   <addition>
      <value>1</value>
      <variable>x</variable>
   </addition>
   <value>8</value>
</addition>

Пояснение: Правильное использование шаблонов, xsl:apply-templates а также xsl:variable,

Другие вопросы по тегам