Сделать документ результата XSLT обработанным "родительским" документом XSLT, рекурсивно

У меня есть документ grandchild.xml, чей результат после обработки с помощью granchild.xsl должен быть перенаправлен в child.xsl, затем он должен быть окончательно обработан и выведен parent.xsl.

Я пытался добавить xml-stylesheet элемент к итоговому документу, ожидая, что он будет обработан с использованием указанной таблицы стилей XSL, но ничего не произошло.

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

2 ответа

Решение

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

Чтобы доказать это, я только что попробовал следующее в IE8, FF14 и Chrome...

level1.xml

<?xml version="1.0" encoding="utf-8" ?> 
<?xml-stylesheet title="XSL_formatting" type="text/xsl" href="level1.xsl"?>
<data>
  <id>Level 1 data</id>
</data>

level1.xsl

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
     <?xml-stylesheet title="XSL_formatting" type="text/xsl" href="level2.xsl"?>
     <data2>
       <id2>Level 2: <xsl:value-of select="/data/id"/></id2>
     </data2>
   </xsl:template>   
</xsl:stylesheet>

level2.xsl

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
     <html>
       <body>
         <b>Level 3:</b> <xsl:value-of select="/data2/id2"/>
       </body>
     </html>
   </xsl:template>   
</xsl:stylesheet>

Результат от всех 3 браузеров просто для отображения Level 2: Level 1 Data,

Вот пример многопроходного преобразования в браузере:

Давайте иметь этот исходный документ XML:

<?xml-stylesheet title="XSL_formatting"
  type="text/xsl" href="MultiPassBrowser.xsl"?>
<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

Давайте получим эти два XSLT-преобразования:

MultiPassBrowser1.xsl

<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="num/text()">
  <xsl:value-of select=". *2"/>
 </xsl:template>
</xsl:stylesheet>

а также

MultiPassBrowser2.xsl

<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()|@*" mode="pass2">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="pass2"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="num" mode="pass2">
  <p><xsl:value-of select=". +1"/></p>
 </xsl:template>
</xsl:stylesheet>

Первое преобразование копирует XML-документ "как есть", но со строковым значением каждого num элемент, умноженный на 2.

Второе преобразование копирует XML-документ "как есть", но со строковым значением каждого num Элемент увеличен.

Если второе преобразование применяется к результату первого, конечные значения, полученные из начального num элементы должны быть 3, 5, 7, ..., 21.

Вот преобразование, которое склеивает эти два:

MultiPassBrowser.xsl

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
 exclude-result-prefixes="ext msxsl">
 <xsl:import href="file:///C:/Temp/delete/MultiPassBrowser1.xsl"/>
 <xsl:import href="file:///C:/Temp/delete/MultiPassBrowser2.xsl"/>
 <xsl:output method="html"/>
 <xsl:strip-space elements="*"/>

 <msxsl:script language="JScript" implements-prefix="ext">
     this['node-set'] =  function (x) {
      return x;
      }
 </msxsl:script>

 <xsl:template match="/">
  <html>
      <xsl:variable name="vrtfPass1">
        <xsl:apply-templates select="/*"/>
      </xsl:variable>

      <xsl:apply-templates select="ext:node-set($vrtfPass1)/*/*"
                           mode="pass2"/>
  </html>
 </xsl:template>
</xsl:stylesheet>

Результат, когда файл XML открывается с помощью IE, Firefox, Safari и Opera, является правильным, ожидаемым:

<html>
   <p>3</p>
   <p>5</p>
   <p>7</p>
   <p>9</p>
   <p>11</p>
   <p>13</p>
   <p>15</p>
   <p>17</p>
   <p>19</p>
   <p>21</p>
</html>

Пояснение:

  1. Основной модуль таблицы стилей (тот, на который ссылается XML-документ PI) импортирует два модуля таблицы стилей, которые содержат отдельные преобразования.

  2. Результат первого преобразования фиксируется в переменной $vrtfPass1,

  3. В XSLT 1.0 такая переменная имеет печально известный тип "RTF" (Result Tree Fragment) и не может работать напрямую (только копирование и string() функция может быть использована на RTF). Здесь мы используем портативный вариант xxx:node-set() функция расширения, которая работает как в IE, так и в других четырех основных браузерах. Это портативное расширение было впервые предложено @DavidCarlisle, а оригинал можно найти в его блоге.

  4. Шаблоны в режиме "pass2" затем применяются к набору узлов, в который мы преобразовали на шаге выше переменную RTF. Все шаблоны во втором импортированном модуле таблиц стилей находятся в режиме "pass2", поэтому они выбраны для выполнения.

  5. Окончательный результат получается.

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