Как я могу использовать xsl: импорт с переменной в имени пути?

#xslt

#xslt

Вопрос:

По сути, я хочу сделать это в XSL:

 <xsl:include href="_domains/{$domain}/templates/header.xsl" />
  

Но, похоже, я не могу использовать переменную ($ domain) во включаемом. Есть предложения по обходному пути?

Комментарии:

1. Хороший вопрос, 1. Смотрите мой ответ о возможном (но ограниченном) решении, доступном только для XSLT 2.0, и другом альтернативном решении, отличном от XSLT.

Ответ №1:

xsl:import и xsl:include разрешаются во время компиляции и не поддерживают расширение среды выполнения.

Кроме того, если вы используете XSLT 2.0, вы можете использовать условное включение с use-when , если у вас есть выражение, которое может быть вычислено в статическом контексте.

Комментарии:

1. 1 правильный ответ. Даже в XSLT 2.0 URI модуля таблицы стилей не является «динамическим». Это может быть относительный URI , конечно…

Ответ №2:

Как объяснил @lavinio, в XSLT 2.0 use-when атрибут может использоваться для обеспечения определенной степени включения инструкции xslt во время компиляции, однако это ограничено только условиями тестирования, которые могут быть определены из значений в статическом контексте и из этих значений динамического контекста: текущая дата и время и неявный часовой пояс.

Другой подход заключается в загрузке таблицы стилей XSLT (в виде XML-документа) во время выполнения и перед инициированием преобразования для динамической установки href атрибута любых желаемых <xsl:include> и / или <xsl:import> инструкций.

Этот метод используется визуализатором XPath для динамического изменения таблицы стилей XSLT, которая затем вычисляет указанное пользователем выражение XPath и форматирует XML-документ, выделяя все выбранные и видимые узлы.

Ответ №3:

С добавлением статических параметров теперь можно условно включать в XSLT 3.0. Статические параметры могут использоваться в use-when атрибуте xsl:include .

Теперь мы можем объявить параметры со значениями по умолчанию false() , а затем переопределить те, которые нам нужны во время выполнения…

 <xsl:param name="someparam" as="xs:boolean" select="false()" 
  static="yes" required="no"/>  
<xsl:include href="include_me.xsl" use-when="$someparam"/>
  

Вот полный рабочий пример, протестированный с Saxon-HE версии 9.7 (также протестированный с Saxon-PE 9.5).

Ввод XML (test.xml )

 <doc>
    <foo/>
</doc>
  

Основной XSLT 3.0 (test_main.xsl)

 <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="inc1" as="xs:boolean" select="false()" 
    static="yes" required="no"/>
  <xsl:param name="inc2" as="xs:boolean" select="false()" 
    static="yes" required="no"/>

  <xsl:include href="test_inc1.xsl" use-when="$inc1"/>
  <xsl:include href="test_inc2.xsl" use-when="$inc2"/>

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

</xsl:stylesheet>
  

Первым возможным включен XSLT 3.0 (test_inc1.xsl)

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

  <xsl:template match="foo">
    <xsl:copy>INCLUDE FILE 1!!!</xsl:copy>
  </xsl:template>

</xsl:stylesheet>
  

Второй возможный вариант включал XSLT 3.0 (test_inc2.xsl)

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

  <xsl:template match="foo">
    <xsl:copy>INCLUDE FILE 2!!!</xsl:copy>
  </xsl:template>

</xsl:stylesheet>
  

Командная строка (значение inc2 равно true)

 java -cp "saxon9he.jar" net.sf.saxon.Transform -s:"test.xml" -xsl:"test_main.xsl" inc2="true"
  

Вывод

 <doc>
   <foo>INCLUDE FILE 2!!!</foo>
</doc>
  

Ответ №4:

Другим решением является загрузка XML-файла и преобразование его по набору правил (этот файл может быть даже простым вариантом XSLT).

 <xsl:param name="domain">_default</xsl:param>

<xsl:variable name="header-template"
   select="document( concat('_domains/', $domain, '/templates/header.xml' ) )" />

<xsl:template name="header">
  <xsl:apply-templates mode="transform" select="$header-template"/>
</xsl:template>