Слияние последовательностей элементов в XSLT - PullRequest
3 голосов
/ 29 октября 2010

У меня есть пачки автоматически сгенерированного HTML, которые делают такие глупые вещи, как это:

 <p>Hey it's <em>italic</em><em>italic</em>!</p>

И я бы хотел сократить это до:

 <p>Hey it's <em>italicitalic</em>!</p>

Моя первая попытка былав соответствии с этим ...

<xsl:template match="em/preceding::em">
    <xsl:value-of select="$OPEN_EM"/>
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="em/following::em">
    <xsl:apply-templates/>
    <xsl:value-of select="$CLOSE_EM"/>
</xsl:template>

Но, очевидно, спецификация XSLT в ее грандиозной доброте запрещает использование стандартных осей XPath preceding или following в сопоставителях шаблонов.(И это все равно потребует некоторой настройки для обработки трех ems подряд.)

Какие-нибудь решения лучше, чем забыть об этом в XSLT и просто запустить replace('</em><em>', '') в $ LANGUAGE_OF_CHOICE для конечного результата?Грубые требования: не следует объединять два <em>, если они разделены чем-либо (пробелами, текстом, тегами), и, хотя им не нужно объединять их, он должен по крайней мере создавать действительный XML, если их три или более <em> в ряд.Обработка тегов, вложенных в ems (включая другие ems), не требуется.

(И, о, я видел , как объединить элемент с помощью xslt? , что похоже, но не совсемТо же самое. XSLT 2, к сожалению, не вариант, и предлагаемые решения выглядят ужасно сложными.)

Ответы [ 2 ]

2 голосов
/ 29 октября 2010

Это также похоже на группирование смежных областей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="em">
        <em>
            <xsl:call-template name="merge"/>
        </em>
        <xsl:apply-templates
             select="following-sibling::node()[not(self::em)][1]"/>
    </xsl:template>
    <xsl:template match="node()" mode="merge"/>
    <xsl:template match="em" name="merge" mode="merge" >
        <xsl:apply-templates select="node()[1]"/>
        <xsl:apply-templates select="following-sibling::node()[1]" 
                             mode="merge"/>
    </xsl:template>
</xsl:stylesheet>

Выход:

<p>Hey it's <em>italicitalic</em>!</p>

Примечание : Правило идентификации тонкого обхода graneid (копировать все, узел за узлом); em правило (всегда первое, потому что процесс - узел за узлом), перенос и вызов шаблона merge, применение шаблона к следующему брату не em; em правило в режиме merge (также называемое merge), применение шаблонов к первому дочернему элементу (в данном случае это просто текстовый узел, но это позволяет использовать вложенные элементы), а затем к следующему брату в режиме merge; Правило "break", сопоставление с чем-либо, кроме em (поскольку проверка имени превосходит проверку типа узла в приоритете), останавливает процесс.

2 голосов
/ 29 октября 2010

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

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kFollowing"
  match="em[preceding-sibling::node()[1][self::em]]"
  use="generate-id(preceding-sibling::node()[not(self::em)][1])"/>

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

 <xsl:template match=
    "em[following-sibling::node()[1][self::em]
      and
        not(preceding-sibling::node()[1][self::em])
       ]">
   <em>
     <xsl:apply-templates select=
     "node()
     |
      key('kFollowing',
           generate-id(preceding-sibling::node()[1])
          )/node()"/>
   </em>
 </xsl:template>
 <xsl:template match=
 "em[preceding-sibling::node()[1][self::em]]"/>
</xsl:stylesheet>

при применении к следующему документу XML (на основе предоставленного документа, но с тремя смежными элементами em):

<p>Hey it's <em>italic1</em><em>italic2</em><em>italic3</em>!</p>

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

<p>Hey it's <em>italic1italic2italic3</em>!</p>

Примечание :

  1. Использование правила идентификации для копирования каждого узла как есть.

  2. Использование ключа для удобного указания следующих смежных em элементов.

  3. Переопределение единичного преобразования только для em элементов , имеющих соседние em элементы.

  4. Это преобразование объединяет любое количество смежных em элементов .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...