Позиционная группировка: преобразование xslt из html

У меня есть следующий html-файл, и я хочу запустить преобразование, чтобы все теги h1, h2, h3 были преобразованы в соответствующие div. h2 всегда будет вложенным div h1, и если есть 2 тега h2, то у него должны быть собственные div. точно так же h3 всегда будет вложенным div h2.

<body>
   <p> this is a text</p>
   <a href="http://yahoo.com">click here</a>
   <h3>this is heading 3</h3>
   <p>text for heading 3</p>
    <h1>
      heading 1
   </h1>
     this is a text for heading 1
     <a href="link"> This is a link </a>
  <h2>
       this is heading 2

  </h2>
          this is a text for heading 2
  <h2>
          this is heading 2 again
  </h2>
         this is a text for heading 2 again
  </body>

"Вывод выше должен быть таким:

<body>
   <p> this is a text</p>
   <a href="http://yahoo.com">click here</a>
   <div>
    <heading>this is heading 3</heading>
   <p>text for heading 3</p>
    <div>

 <div>
  <heading>
    heading 1
  </heading>
  this is a text for heading 1
  <a href="link"> This is a link </a>
  <div>
    <heading>
           this is heading 2
      </heading>
     this is a text for heading 2
 </div>
 <div>
    <heading>
          this is heading 2 again
    </heading>
          this is a text for heading 2 again
  </div>
</div>
</body>

Любая помощь будет оценена. В настоящее время я сделал это в asp.net, но хочу преобразовать это в xslt.


person atif    schedule 30.08.2011    source источник
comment
Я думаю, вам понадобится корневой элемент в исходной разметке, поэтому, если ваш HTML выглядит точно так, как вы опубликовали, он не может работать.   -  person DanMan    schedule 30.08.2011
comment
Привет, DanMan, я добавил тело корневого элемента.   -  person atif    schedule 30.08.2011
comment
Хороший вопрос, +1. См. мой ответ для полного решения XSLT 1.0, которое является простым, очень коротким (значительно короче, чем представленное решение XSLT 2.0) и эффективным - с использованием ключей.   -  person Dimitre Novatchev    schedule 31.08.2011


Ответы (1)


Вот таблица стилей XSLT 2.0:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs mf"
  version="2.0">

  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>

  <xsl:function name="mf:group" as="node()*">
    <xsl:param name="nodes" as="node()*"/>
    <xsl:param name="level" as="xs:integer"/>
    <xsl:param name="max-level" as="xs:integer"/>
    <xsl:choose>
      <xsl:when test="$level le $max-level">
        <xsl:for-each-group select="$nodes" group-starting-with="*[local-name() eq concat('h', $level)]">
          <xsl:choose>
            <xsl:when test="self::*[local-name() eq concat('h', $level)]">
              <div>
                <xsl:apply-templates select="."/>
                <xsl:sequence select="mf:group(current-group() except ., $level + 1, $max-level)"/>
              </div>
            </xsl:when>
            <xsl:otherwise>
              <xsl:apply-templates select="current-group()"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:for-each-group>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="$nodes"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

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

  <xsl:template match="*[h1]">
    <xsl:copy>
      <xsl:sequence select="mf:group(node(), 1, 3)"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="h1 | h2 | h3">
    <heading>
      <xsl:apply-templates/>
    </heading>
  </xsl:template>

</xsl:stylesheet>

При подаче с Saxon 9.3 на вход

<body>
 <h1>
    heading 1
 </h1>
     this is a text for heading 1
     <a href="link"> This is a link </a>
  <h2>
       this is heading 2

  </h2>
          this is a text for heading 2
  <h2>
          this is heading 2 again
  </h2>
         this is a text for heading 2 again
</body>

Я получаю следующий вывод

<body>
   <div>
      <heading>
    heading 1
 </heading>
     this is a text for heading 1
     <a href="link"> This is a link </a>
      <div>
         <heading>
       this is heading 2

  </heading>
          this is a text for heading 2
  </div>
      <div>
         <heading>
          this is heading 2 again
  </heading>
         this is a text for heading 2 again
</div>
   </div>
</body>

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

person Martin Honnen    schedule 30.08.2011