XSLT условное включение внешнего файла - PullRequest
6 голосов
/ 24 января 2012

Я хочу выполнить условное включение в XSLT, но xsl: include - это элемент верхнего уровня. Вы можете использовать только xsl: if или xsl: select внутри шаблона. Есть ли какой-либо вид взлома или обходного пути, который позволяет условно включить внешний файл? Я попытался использовать функцию document (), но мне не удалось загрузить внешний файл (возможно, потому, что он не соответствует некоторому набору правил, которые делали бы его «действительным»).

Мой внешний XML-файл представляет собой набор фрагментов кода xslt. в зависимости от значения переменной в основном файле XSLT соответствующий код из внешнего файла должен быть «скопирован / вставлен» на месте (как условное включение в C или PHP).

Поток моего основного файла XSLT должен выполняться следующим образом:

$configurationMode
if ( $configurationMode = Standard ) { xsl:include="standard.xml" } else { xsl:include="alt.xml" }

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

Ответы [ 8 ]

6 голосов
/ 25 января 2012

Это не может быть сделано с XSLT 1.0 и может быть сделано (в очень ограниченной степени) в XSLT 2.0 с использованием атрибута use-when .

Существуют не-xslt способы достижения требуемого динамического изменения директивы xsl:include или xsl:import.

Одним из таких методов является загрузка таблицы стилей XSLT в качестве XmlDocument и использование доступных методов DOM для доступа и изменения атрибутов, чтобы установить для атрибута href желаемое значение. Затем запустите преобразование из этой таблицы стилей XSLT, содержащей XMLDocument и модифицированной в памяти.

3 голосов
/ 25 января 2012

Попробуйте инвертировать структуру: если у вас есть два специальных модуля pink.xsl и blue.xsl и универсальный модуль baby.xsl, тогда вместо попытки импортировать / включить один из pink.xsl или blue.xslв baby.xsl, вместо этого используйте pink.xsl или blue.xsl в качестве таблицы стилей записи верхнего уровня, и каждый из этих двух импортирует baby.xsl.Это способ, которым он был разработан для использования, это не хак или обходной путь.

В качестве альтернативы, учитывая это описание вашего сценария «Мой внешний XML-файл представляет собой набор фрагментов кода xslt», лучший подход вВаш случай может состоять в том, чтобы собрать таблицу стилей из этих фрагментов как отдельный шаг, используя преобразование XSLT вместо использования xsl: include / xsl: import.

3 голосов
/ 24 января 2012

Как я понимаю, «include» происходит, когда синтаксический анализатор xml анализирует и компилирует таблицу стилей.Это означает, что никакая логика или оценка выражения не может произойти до того, как будет обработано включение, и, следовательно, нет способа сделать его условным как таковым.Вам нужно, чтобы условное поведение происходило за пределами таблицы стилей.

Посмотрите на это http://www.dpawson.co.uk/xsl/sect2/N4760.html#d6065e100

В частности, этот комментарий Майка Кея поможет:

Это было поднято несколько раз.В предыдущем потоке мы пришли к выводу, что пользователь пытался написать универсальную таблицу стилей G, а затем специализировать ее путем условного включения специальной таблицы стилей A или B. Чтобы выполнить это требование, нужно иметь A и Bвключите G, а не наоборот, и тогда вы условно выбираете A или B в качестве основной таблицы стилей при запуске преобразования.

1 голос
/ 17 июня 2014

Не уверен, применимо ли это к вашему сценарию, но я все равно добавлю это.

В прошлом я делал подобные вещи, но вместо условного включения я вызываю шаблон в любом из двух файлов, основываясь на том, что вычисляет xsl: when. Если вы не хотите использовать шаблоны в вашем случае, не обращайте внимания на этот ответ.

Например, допустим, что «родительский» xslt-файл называется root.xslt , а два условно используемых: child1.xslt и child2.xslt . Скажем, я хочу запустить условную логику для значения узла с именем status . Если значение «CURRENT», я хочу вызвать шаблон с именем isCurrent в child1.xslt, в противном случае вызвать шаблон с именем isNotCurrent в child2.xslt. Для краткости в каждом случае я просто передаю шаблон корневому узлу и всем дочерним элементам.

Это будет выглядеть примерно так:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:import href="child1.xslt"/>
    <xsl:import href="child2.xslt"/>

    <xsl:template match="/">
      <xsl:choose>
        <xsl:when test="rootNode/status = 'CURRENT'">
          <!-- template isCurrent defined in child1.xslt -->
          <xsl:apply-templates select="rootNode" mode="isCurrent" />
        </xsl:when>
        <xsl:otherwise>
          <!-- template isNotCurrent defined in child2.xslt -->
          <xsl:apply-templates select="rootNode" mode="isNotCurrent" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Надеюсь, это хотя бы немного поможет.

0 голосов
/ 08 декабря 2017

Существует один подход, который я нашел для условного включения файлов с использованием функции use-when в XSLT 2.0.

Вы должны создать одно системное свойство, которое передается через приложение во время выполнения, как в моем случае я использую Java, поэтому я создал свойство «Debug», используя команду для запуска моего приложения:

java -DDebug=yes myAppPath

затем в XSLT используйте это свойство для включения условных файлов. Например

<xsl:include href="file1.xslt" use-when="system-property('DEBUG') = 'yes'"/>
<xsl:include href="file2.xslt" use-when="system-property('DEBUG') != 'yes'"/>

вот так.

Не знаю, подходит ли он для заданного сценария, но ДА, есть способ сделать это в XSLT 2.0. В XSLT 3.0 также добавлена ​​поддержка локальной переменной. Так что это легко сделать с помощью локальных переменных.

Спасибо, Счастливое кодирование

0 голосов
/ 01 марта 2017

С добавлением статических параметров это теперь возможно в 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 v9.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>
0 голосов
/ 21 мая 2013
<xsl:variable name="CONDITIONAL" select="ELEMENT/CONDITION"/>
<xsl:variable name="DOCUMENTNAME" select="document(concat($CONDITIONAL,'-DOCUMENT.xml'))/ELEMENT"/>

В этом примере показано, как я сделал условное использование внешнего файла. У меня был флаг в базовом XML, который XSL использует в качестве переменной, чтобы помочь указать имя другого файла для добавления в шаблон. Как только эта переменная определена, как в моем случае, я использую ее для извлечения других данных XML в сгенерированный вывод. Команда concat объединяет данные, чтобы дать имя файла.

Итак, когда мне нужна информация из внешнего XML-файла, я использую $ DOCUMENTNAME для ссылки на внешние данные.

0 голосов
/ 25 января 2012

В дополнение к тому, что уже было сказано, возможное решение состоит в том, чтобы сделать дополнительные файлы простыми, предоставляющими контент XML-файлами (вместо файлов XSLT). Таким образом, вы можете включить их с функцией XPath document() (которая будет оцениваться во время выполнения, а не во время компиляции).

Затем вы можете изменить поведение вашего преобразования на основе содержимого загруженного XML-документа; однако вы не можете предоставить исполняемые фрагменты XSLT во включенных документах.

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

Если у вас проблемы с document(), используйте для ваших файлов валидатор XML. Ошибка означает, что ваши файлы не являются допустимыми XML.

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