XSLT 3.0 Динамический выбор с переменной в apply-шаблонах? - PullRequest
0 голосов
/ 08 мая 2018

Я хочу применить шаблоны к набору узлов, где часть пути select является переменной.Я использую Saxon-HE 9.8 (потрясающая библиотека!)

Я пытаюсь добиться следующего

<variable name="x" select="string('baz')"/>
<xsl:apply-templates select="foo/bar/$x"/>

Это не похоже на работу.Есть ли синтаксис, который позволит мне динамически создавать select XPath для этой инструкции apply-templates?Или есть другой метод для динамического достижения этого эффекта?Я даже пытался опустить это до моего <xsl:template match=foo/bar/$x>, но не повезло.

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

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Если вы объявляете статический параметр <xsl:param name="x" static="yes" as="xs:string" select="'baz'"/> для значения, а затем используете теневой атрибут в виде _select="foo/bar/{$x}", вы даже можете построить путь динамически, но только при компиляции XSLT.

В статическом параметре вы, конечно, можете получить файл конфигурации и использовать значения из него:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    version="3.0">

  <xsl:param name="config-uri" static="yes" as="xs:string" select="'https://martin-honnen.github.io/xslt/2018/config-example1.xml'"/>
  <xsl:param name="config-doc" static="yes" as="document-node()" select="doc($config-uri)"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="item[@type = 'foo']">
      <xsl:copy>
          <xsl:value-of _select="{$config-doc/map/from[@key = 'foo']}"/>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="item[@type = 'bar']">
      <xsl:copy>
          <xsl:value-of _select="{$config-doc/map/from[@key = 'bar']}"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / 6qVRKvX / 1

Еще один вариант, который я не упомянул в своем первом ответе, но он также приемлем с Saxon 9.8 или любым другим процессором XSLT 3 - это использование XSLT для создания XSLT и последующего использования функции transform (https://www.w3.org/TR/xpath-functions/#func-transform) для запуска этого сгенерированного XSLT. Преимущество этого подхода в том, что он работает с Saxon 9.8 HE, где xsl:evaluate не поддерживается:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
    exclude-result-prefixes="axsl"
    version="3.0">

  <xsl:param name="config-uri" as="xs:string" select="'https://martin-honnen.github.io/xslt/2018/config-example1.xml'"/>
  <xsl:param name="config-doc" as="document-node()" select="doc($config-uri)"/>

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

  <xsl:variable name="generated-xslt">
      <axsl:stylesheet version="3.0">
          <axsl:mode on-no-match="shallow-copy"/>
          <xsl:for-each select="$config-doc/map/from">
              <axsl:template match="item[@type = '{@key}']">
                  <axsl:copy>
                      <axsl:value-of select="{.}"/>
                  </axsl:copy>
              </axsl:template>
          </xsl:for-each>
      </axsl:stylesheet>
  </xsl:variable>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="/">
      <xsl:sequence 
        select="transform(map {
            'source-node' : .,
            'stylesheet-node' : $generated-xslt
          })?output"/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / 6qVRKvX / 2

0 голосов
/ 08 мая 2018

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

<xsl:apply-templates select="foo/bar/*[local-name() = $x]"/>

С Saxon-PE или Saxon-EE вы можете использовать xsl:evaluate и сделать что-то вроде этого:

<xsl:variable name="var" as="node()*">
  <xsl:evaluate xpath="concat('foo/bar/',$x)" context-item="."/>
</xsl:variable>
<xsl:apply-templates select="$var"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...