#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>