как объединить элемент с помощью xslt?

У меня есть ссылочный тип абзаца с элементом.

Пример

Входной файл:

<reference>
<emph type="bold">Antony</emph><emph type="bold">,</emph> <emph type="bold">R.</emph>
<emph type="bold">and</emph> <emph type="bold">Micheal</emph><emph type="bold">,</emph> <emph type="bold">V.</emph>
<emph type="italic">reference title</emph></reference>

Вывод получен сейчас:

<p class="reference"><strong>Antony</strong><strong>,</strong> <strong>R.</strong>
<strong>and</strong> <strong>Micheal</strong><strong>,</emph>
<emph type="bold">V.</strong> <em>reference title></em></p>

Требуемый выходной файл:

<p class="reference"><strong>Antony, R. and Micheal, V.</strong> <em>reference title</em></p>

Мои xslt-скрипты:

<xsl:template match="reference">
<p class="reference"><xsl:apply-templates/></p>
</xsl:template>

<xsl:template match="emph">
<xsl:if test="@type='bold'">
<strong><xsl:apply-templates/></strong>
</xsl:if>
<xsl:if test="@type='italic'">
<em><xsl:apply-templates/></em>
</xsl:if>
</xsl:template>

Что нужно исправить в xslt, чтобы получить элемент <strong> единожды, как и требуемый выходной файл?

Посоветуйте кто нибудь..

Автор, Энтни.


person Community    schedule 09.10.2009    source источник
comment
Вы можете позволить себе роскошь использовать XSLT 2.0? Если это так, используйте ‹xsl:for-each-group› и group-adjaxe. В противном случае это сложнее, но возможно.   -  person Evan Lenz    schedule 09.10.2009
comment
Мой вопрос заключается в том, почему входной файл проходит с несколькими узлами ‹emph› вместо одного ‹emph› вокруг всей строки, которую вы хотите выделить жирным шрифтом?   -  person Keith    schedule 09.10.2009


Ответы (2)


Это решение XSLT 1.0:

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="xml" encoding="utf-8" />

  <!-- the identity template copies everything verbatim -->    
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <!-- this matches the first <emph> nodes of their kind in a row -->    
  <xsl:template match="emph[not(@type = preceding-sibling::emph[1]/@type)]">
    <xsl:variable name="elementname">
      <xsl:choose>
        <xsl:when test="@type='bold'">strong</xsl:when>
        <xsl:when test="@type='italic'">em</xsl:when>
      </xsl:choose>
    </xsl:variable>
    <xsl:if test="$elementname != ''">
      <!-- the first preceding node with a different type is the group separator -->
      <xsl:variable 
        name="boundary" 
        select="generate-id(preceding-sibling::emph[@type != current()/@type][1])
      " />
      <xsl:element name="{$elementname}">
        <!-- select all <emph> nodes of the row with the same type... -->
        <xsl:variable 
          name="merge" 
          select=". | following-sibling::emph[
            @type = current()/@type
            and 
            generate-id(preceding-sibling::emph[@type != current()/@type][1]) = $boundary
          ]"
        />
        <xsl:apply-templates select="$merge" mode="text" />
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <!-- default: keep <emph> nodes out of the identity template mechanism -->
  <xsl:template match="emph" />

  <!-- <emph> nodes get their special treatment here -->
  <xsl:template match="emph" mode="text">
    <!-- effectively, this copies the text node via the identity template -->
    <xsl:apply-templates />

    <!-- copy the first following node - if it is a text node
         (this is to get interspersed spaces into the output) -->
    <xsl:if test="
      generate-id(following-sibling::node()[1])
      =
      generate-id(following-sibling::text()[1])
    ">
      <xsl:apply-templates select="following-sibling::text()[1]" />
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Это приводит к:

<reference>
  <strong>Antony, R. and Micheal, V.</strong>
  <em>reference title</em>
</reference>

я не слишком доволен

<xsl:variable 
  name="merge" 
  select=". | following-sibling::emph[
    @type = current()/@type
    and 
    generate-id(preceding-sibling::emph[@type != current()/@type][1]) = $boundary
  ]"
/>

если у кого-то есть идея получше, скажите, пожалуйста.

person Tomalak    schedule 09.10.2009

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

Сначала он соответствует первому элементу 'emph', а затем рекурсивно вызывает шаблон, соответствующий элементам 'emph' того же типа. Затем он повторяет процесс сопоставления следующего элемента 'emph' типа, отличного от того, который соответствует в данный момент.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:output method="html" encoding="utf-8"/>

   <!-- Match root element -->
   <xsl:template match="reference">
      <p class="reference">
         <!-- Match first emph element -->
         <xsl:apply-templates select="emph[1]"/>
      </p>
   </xsl:template>

   <!-- Used to match first occurence of an emph element for any type -->
   <xsl:template match="emph">
      <xsl:variable name="elementname">
         <xsl:if test="@type='bold'">strong</xsl:if>
         <xsl:if test="@type='italic'">em</xsl:if>
      </xsl:variable>
      <xsl:element name="{$elementname}">
         <xsl:apply-templates select="." mode="match">
            <xsl:with-param name="type" select="@type"/>
         </xsl:apply-templates>
      </xsl:element>
      <!-- Find next emph element with a different type -->
      <xsl:apply-templates select="following-sibling::emph[@type!=current()/@type][1]"/>
   </xsl:template>

   <!-- Used to match emph elements of a specific type -->
   <xsl:template match="*" mode="match">
      <xsl:param name="type"/>
      <xsl:if test="@type = $type">
         <xsl:value-of select="."/>
         <xsl:apply-templates select="following-sibling::*[1]" mode="match">
            <xsl:with-param name="type" select="$type"/>
         </xsl:apply-templates>
      </xsl:if>
   </xsl:template>
</xsl:stylesheet>

Однако в настоящее время это не удается, так как он не соответствует пробелу между элементами «emph».

person Tim C    schedule 11.10.2009