Какие есть полезные конструкции для использования XSLT для создания XSLT?

У меня есть существующая таблица стилей XSLT, которая принимает XML и создает красиво отформатированный XHTML. Я хочу сделать версию этой таблицы стилей XSL-FO для создания PDF через Apache FOP. Я хочу знать следующее:

Есть ли удобные для использования шаблоны xslt, которые мне нужно научиться делать, например:

  • копирование некоторых узлов без изменений
  • копирование большей части узла, но добавление дополнительных атрибутов

Я знаю, что могу создавать новые узлы, используя

<xsl:element>

но есть ли какие-либо другие полезные вещи, которые мне понадобятся. Обратите внимание, что, хотя я не много копировал из одного формата XSLT в другой, я сделал ТОННЫ XML-> XHTML через XSLT, поэтому я знаком с большей частью ядра языка.


person Jay Stevens    schedule 04.06.2009    source источник


Ответы (3)


Шаблон, который вы ищете, - это "модифицированное преобразование идентичности". Основой этого подхода является правило преобразования идентификаторов, первое правило шаблона в таблице стилей ниже. Каждое правило после этого представляет собой исключение из поведения копирования.

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

  <!-- By default, copy all nodes unchanged -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- But strip out <foo> elements (including their content) -->
  <xsl:template match="foo"/>

  <!-- For <bar> elements, strip out start & end tags, but leave content --> 
  <xsl:template match="bar">
    <xsl:apply-templates/>
  </xsl:template>

  <!-- For <bat> elements, insert an attribute and append a child --> 
  <xsl:template match="bat">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="id">123</xsl:attribute>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Что меня меньше всего удовлетворяет в вышеизложенном, так это дублирование логики в последнем правиле шаблона. Слишком много кода для добавления одного атрибута. И представьте, если нам понадобится их куча. Вот еще один подход, который позволяет нам быть более хирургически точными в том, что мы хотим переопределить:

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

  <!-- By default, copy all nodes unchanged -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates mode="add-atts" select="."/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

          <!-- By default, don't add any attributes -->
          <xsl:template mode="add-atts" match="*"/>

  <!-- For <bat> elements, insert an "id" attribute -->
  <xsl:template mode="add-atts" match="bat">
    <xsl:attribute name="id">123</xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

Наконец, это можно продвинуть гораздо дальше, используя разные режимы для каждого типа редактирования, которое вы, возможно, захотите сделать:

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

  <!-- For <bat> elements, insert an "id" attribute -->
  <xsl:template mode="add-atts" match="bat">
    <xsl:attribute name="id">123</xsl:attribute>
  </xsl:template>

  <!-- Append <new-element/> to <bat> -->
  <xsl:template mode="append" match="bat">
    <new-element/>
  </xsl:template>

  <!-- Insert an element in <foo> content -->
  <xsl:template mode="insert" match="foo">
    <inserted/>
  </xsl:template>

  <!-- Add content before the <bar/> and <bat/> elements -->
  <xsl:template mode="before" match="bar | bat">
    <before-bat-and-bar/>
  </xsl:template>

  <!-- Add content only after <bat/> -->
  <xsl:template mode="after" match="bat">
    <after-bat/>
  </xsl:template>

  <!-- Here's the boilerplate code -->
  <!-- By default, copy all nodes unchanged -->
  <xsl:template match="@* | node()">
    <xsl:apply-templates mode="before" select="."/>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates mode="add-atts" select="."/>
      <xsl:apply-templates mode="insert" select="."/>
      <xsl:apply-templates/>
      <xsl:apply-templates mode="append" select="."/>
    </xsl:copy>
    <xsl:apply-templates mode="after" select="."/>
  </xsl:template>

          <!-- By default, don't add anything -->
          <xsl:template mode="add-atts" match="*"/>
          <xsl:template mode="insert"   match="*"/>
          <xsl:template mode="append"   match="*"/>
          <xsl:template mode="before"   match="@* | node()"/>
          <xsl:template mode="after"    match="@* | node()"/>

</xsl:stylesheet>

В XSLT 2.0 некоторые шаблоны могут быть немного упрощены благодаря многорежимным правилам шаблона:

          <!-- By default, don't add anything -->
          <xsl:template mode="add-atts
                              insert
                              append
                              before
                              after" match="@* | node()"/>

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

person Evan Lenz    schedule 05.06.2009
comment
Извините, это заняло некоторое время. Это именно то, что я хотел (я думаю). Мне нужно еще немного протестировать его. - person Jay Stevens; 10.06.2009

Самым большим препятствием для преобразования XSLT является то, что префикс выходного пространства имен совпадает с префиксом реальных инструкций XSL в вашем преобразовании. Если вы используете «xsl:» как в своих инструкциях XSL, так и в выводе, ваш механизм XSLT не будет знать разницу между инструкциями XSL, которые он должен выполнять, и теми, которые он должен выводить, поэтому ваш XSLT не будет анализировать. То есть, если вы не используете псевдоним пространства имен:

<xsl:namespace-alias stylesheet-prefix="x" result-prefix="xsl"/>

Эта инструкция, расположенная внутри <xsl:stylesheet />, позволяет вам записать разметку результата в вашем преобразовании, используя замещающий префикс пространства имен. Позже, когда выходной документ будет создан, префикс, который вы действительно хотите, будет вставлен вместо псевдонима. Так, например, вот шаблон, который создает шаблон в вашем выходном документе:

<xsl:template match="xsl:template[@match='title']>
   <x:template match="title>
      <x:apply-templates />
   </x:template>
</xsl:template>

Вот хорошая статья: http://www.xml.com/pub/a/2001/04/04/trxml/

person James Sulak    schedule 04.06.2009
comment
Что ж, у xslt есть другое пространство имен xslt, вы также можете его использовать! - person alamar; 05.06.2009
comment
w3.org/1999/XSL/Transform — обычное пространство имен, а w3.org/1999/XSL/TransformAlias — еще один :) - person alamar; 05.06.2009

Раньше я разрабатывал таблицы стилей XSL-FO, а затем использовал таблицу стилей Render-X FO2HTML для преобразования XSL-FO в HTML. Он преобразует элементы <block> в <div>, <inline> в <span> и т. д.

Я не использовал их раньше, но вы можете попробовать таблицы стилей HTML2FO. Или, по крайней мере, просматривая их, чтобы позаимствовать некоторые идеи.

Поскольку в HTML отсутствуют некоторые конструкции разбиения на страницы, которые предоставляет FO, он может не дать вам всего, что вам нужно для вывода XSL-FO, но, вероятно, может обрабатывать большую часть логики преобразования из HTML в элемент/атрибуты XSL-FO в тело документа.

person Mads Hansen    schedule 21.08.2009