Рекурсивно применять шаблоны к результирующему дереву в XSLT (постоянное свертывание) - PullRequest
2 голосов
/ 28 декабря 2011

Я пытаюсь применить постоянное свертывание к представлениям 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 Ответ

2 голосов
/ 28 декабря 2011

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

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

...