2016-09-06 3 views
0

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

На самом деле, у меня есть потребность в различных видах XHTML и XML, и, возможно, несколько различных сценариев, но я приведу пример в XHTML для простоты, чтобы найти общее решение этой проблемы:

Say I есть таблица HTML, как это:

<table frame="void"> 
     <col width="50%" /> 
     <col width="50%" /> 
     <thead> 
      <tr> 
       <th></th> 
       <th></th> 
      </tr> 
     </thead> 
     <tbody> 
      <tr> 
       <td>text text <b>text</b> text <i>text</i> text</td> 
       <td>text text <b>text</b> text <i>text</i> text<img src="mypic.png" alt="mypic" 
        />text <b>text</b> text</td> 
      </tr> 
      <tr> 
       <td> 
        <table frame="void"> 
         <col width="50%" /> 
         <col width="50%" /> 
         <thead> 
          <tr> 
           <th></th> 
           <th></th> 
          </tr> 
         </thead> 
         <tbody> 
          <tr> 
           <td></td> 
           <td></td> 
          </tr> 
          <tr> 
           <td></td> 
           <td></td> 
          </tr> 
         </tbody> 
        </table> 
       </td> 
       <td><img src="mypic.png" alt="mypic" /></td> 
      </tr> 
      <tr> 
       <td></td> 
       <td></td> 
      </tr> 
     </tbody> 
    </table> 

и то, что я хочу сейчас, чтобы обернуть все текстовые и встроенные элементы в ячейках таблицы с <p> тегами, чтобы получить это:

<table frame="void"> 
     <col width="50%" /> 
     <col width="50%" /> 
     <thead> 
      <tr> 
       <th></th> 
       <th></th> 
      </tr> 
     </thead> 
     <tbody> 
      <tr> 
       <td> 
        <p>text text <b>text</b> text <i>text</i> text</p> 
       </td> 
       <td><p>text text <b>text</b> text <i>text</i> text</p><img src="mypic.png" 
         alt="mypic" /><p>text <b>text</b> text</p></td> 
      </tr> 
      <tr> 
       <td> 
        <table frame="void"> 
         <col width="50%" /> 
         <col width="50%" /> 
         <thead> 
          <tr> 
           <th></th> 
           <th></th> 
          </tr> 
         </thead> 
         <tbody> 
          <tr> 
           <td></td> 
           <td></td> 
          </tr> 
          <tr> 
           <td></td> 
           <td></td> 
          </tr> 
         </tbody> 
        </table> 
       </td> 
       <td><img src="mypic.png" alt="mypic" /></td> 
      </tr> 
      <tr> 
       <td></td> 
       <td></td> 
      </tr> 
     </tbody> 
    </table> 

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

Также обратите внимание, что на одном из изображений есть окружающий текст и встроенные элементы. В таком случае текст и строка перед изображением должны быть обернуты в тег p перед изображением (или таблицей или любым другим не-встроенным элементом, который может быть), а текст/строка после изображения должны быть завернуты в другой тег p. (В этом случае использование img считается не встроенным элементом btw).

При этом в XSLT 2.0 Я использовал этот шаблон, чтобы справиться с этим, назвав его от шаблона для ячеек таблицы, а не только применяя детские шаблоны:

<xsl:template name="wrapInPara"> 
    <xsl:apply-templates select="@class"></xsl:apply-templates> 
    <xsl:for-each-group select="node()[not(self::text() and normalize-space(.) = '')]"    
     group-adjacent="boolean(self::text() | self::e:b | self::e:i | self::e:em | self::e:strong | self::e:a | self::e:u | self::e:span)"> 
     <xsl:choose> 
      <xsl:when test="current-grouping-key()"> 
       <p>       
        <xsl:apply-templates select="current-group()"/> 
       </p> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:apply-templates select="current-group()"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:for-each-group> 
</xsl:template> 

И называть это что-то вроде этого:

<xsl:template match="td"> 
    <xsl:copy> 
     <xsl:call-template name="wrapInPara"/> 
    </xsl:copy> 
</xsl:template> 

(Как вы можете видеть, что есть больше, чем <b> и <i> тегов, которые необходимо учитывать, и это может быть и другие теги, чем вложенные таблицы или изображения, которые должны быть исключены из упаковки, так что я надеюсь ans которые могут быть изменены для аналогичных вариантов использования, если это возможно.

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

Любая помощь очень ценится!

ответ

2

Вот один из способов сделать это. Фактически он группирует элемент «para» первым предшествующим братом, который не является элементом «para». Затем узел wrapInPara выбирает элементы без «пара» и обертывает любые следующие «пара» элементы (используя ключ) в теге p.

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

    <xsl:key name="para" 
      match="text()|b|i|em|strong|a|u|span" 
      use="concat(generate-id(..), '|', generate-id(preceding-sibling::node()[not((self::text()|self::b|self::i|self::em|self::strong|self::a|self::u|self::span))][1]))" /> 

    <xsl:template name="wrapInPara"> 
     <xsl:apply-templates select="@class" /> 
     <!-- Handle `para` elements that have no preceding non-para nodes --> 
     <xsl:call-template name="groupInPara"> 
      <xsl:with-param name="group" select="key('para', concat(generate-id(), '|'))" /> 
     </xsl:call-template> 
     <xsl:for-each select="node()[not((self::text()|self::b|self::i|self::em|self::strong|self::a|self::u|self::span))]"> 
      <xsl:apply-templates select="." /> 
      <!-- Wrap any following `para` elements --> 
      <xsl:call-template name="groupInPara"> 
       <xsl:with-param name="group" select="key('para', concat(generate-id(..), '|', generate-id()))" /> 
      </xsl:call-template> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template name="groupInPara"> 
     <xsl:param name="group" /> 
     <xsl:if test="$group"> 
      <p> 
       <xsl:apply-templates select="$group" /> 
      </p> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="td"> 
     <xsl:copy> 
      <xsl:call-template name="wrapInPara"/> 
     </xsl:copy> 
    </xsl:template> 

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

SE говорит, чтобы избежать благодарности, но это было бы грубо. И у меня есть комментарий в любом случае только для полноты, вы просто ошибочно оставили версию 2.0, которую я исправил до 1.0, но тогда она отлично работает, спасибо большое! – Anders

Смежные вопросы