Использование XSLT 1.0 для переноса родственных элементов заголовка - PullRequest
2 голосов
/ 07 марта 2011

Я работаю с XSLT 1.0 из PHP и хочу обернуть все родственные элементы после заголовка (h2) в div, чтобы я мог их переключать.

Ввод будет выглядеть как

...
<h2>Nth title</h2>
<first child>...</first child>
...
<last child>...</last child>
<h2>N+1st title</h2>
...

и вывод должен быть

...
<h2>Nth title</h2>
<div>
  <first child>...</first child>
  ...
  <last child>...</last child>
</div>
<h2>N+1st title</h2>
...

Есть ли способ сделать это в XSLT 1.0?

Ответы [ 2 ]

2 голосов
/ 07 марта 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:key name="kFollowing" match="node()[not(self::h2)]"
  use="generate-id(preceding-sibling::h2[1])"/>

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

 <xsl:template match="h2">
  <xsl:call-template name="identity"/>
  <div>
   <xsl:apply-templates mode="copy"
       select="key('kFollowing', generate-id())"/>
  </div>
 </xsl:template>

 <xsl:template match="node()[not(self::h2)][preceding-sibling::h2]"/>

 <xsl:template match="node()" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>
</xsl:stylesheet>

при применении к этому документу XML:

<html>
    <h2>Nth title</h2>
    <first-child>...</first-child> ... 
    <last-child>...</last-child>
    <h2>N+1st title</h2> ...
    <x/>
     <y/>
     <z/>
</html>

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

<html>
   <h2>Nth title</h2>
   <div>
      <first-child>...</first-child> ... 

      <last-child>...</last-child>
   </div>
   <h2>N+1st title</h2>
   <div> ...

      <x></x>
      <y></y>
      <z></z>
   </div>
</html>

Объяснение

  1. Правило / шаблон идентификации копирует каждый узел "как есть".

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

  3. Узлы, которые нужно включить в предыдущий шаг, удобно определить как инструкцию <xsl:key>.

  4. Для того, чтобы узлы, включенные в div, снова выводились правилом идентификации, мы предоставляем шаблон, соответствующий таким узлам, который просто игнорирует их.

0 голосов
/ 07 марта 2011

Да. Сделайте шаблон, который соответствует элементам h2; в этом шаблоне вы можете выбрать всех следующих братьев и сестер до следующего h2, используя это выражение xpath: following-sibling::*[count(preceding-sibling::h2[1] | current()) = 1].

...