Подтвердить что ты не робот

XSLT: создание карты в XSLT

Я хочу иметь ключевую карту значений в xsl и так определенную переменную, которая имеет xml-фрагмент, но позже, когда я пытаюсь получить доступ к узлам xml в переменной, я получаю сообщение об ошибке, что тип xpath-выражения не может быть разрешен.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <xsl:variable name="map">
            <map>
                <entry key="key-1">value1</entry>
                <entry key="key-2">value2</entry>
                <entry key="key-3">value3</entry>
            </map>
        </xsl:variable>
        <output>
            <xsl:value-of select="$map/entry[@key='key-1']"/>
        </output>
    </xsl:template>
</xsl:stylesheet>
4b9b3361

Ответ 1

XSLT 2.0

Используя XSLT 2.0, работает следующее решение:

  <xsl:variable name="map">
    <entry key="key-1">value1</entry>
    <entry key="key-2">value2</entry>
    <entry key="key-3">value3</entry>
  </xsl:variable>

  <xsl:template match="/">
    <output>
      <xsl:value-of select="$map/entry[@key='key-1']"/>
    </output>
  </xsl:template>

XSLT 1.0

Вы не можете использовать фрагмент дерева результатов в выражении XPath в XSLT 1.0, но fn:document() может извлекать значения карты. Ответ на аналогичный вопрос будет работать здесь:.

<xsl:value-of select="document('')//xsl:variable[@name='map']/map/entry[@key='key-1']"/>

Как описано в спецификации XSLT 1.0:

document('') относится к корню nodeтаблица стилей; дерево представление таблицы стилей точно так же, как если бы XML документ, содержащий таблицу стилей, был исходный исходный документ.

Однако для этого вам не нужно использовать xsl:variable. Вы можете указать свою карту node непосредственно под xsl:stylesheet, но вы должны помнить, что элементы верхнего уровня должны иметь URI непустого пространства имен:

<xsl:stylesheet 
  version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:my="some.uri" exclude-result-prefixes="my">

  <my:map>
    <entry key="key-1">value1</entry>
    <entry key="key-2">value2</entry>
    <entry key="key-3">value3</entry>
  </my:map>

  <xsl:template match="/">
    <output>
      <xsl:value-of select="document('')/*/my:map/entry[@key='key-1']"/>
    </output>
  </xsl:template>
</xsl:stylesheet>

Ответ 2

Вы можете сортировать работу вокруг XSLT 1.0 без поддержки использования содержимого переменной в качестве набора node. Вам придется полагаться на расширения, добавленные производителем парсера. Например, Microsoft предложила использовать эту функцию: node -set()

Ваш XSL будет выглядеть так:

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:template match="/">
        <xsl:variable name="map">
            <map>
                <entry key="key-1">value1</entry>
                <entry key="key-2">value2</entry>
                <entry key="key-3">value3</entry>
            </map>
        </xsl:variable>
        <output>
            <xsl:value-of select="msxsl:node-set($map)/map/entry[@key='key-1']"/>
        </output>
    </xsl:template>
</xsl:stylesheet>

Обратите внимание на пространство имен и префикс msxsl. Это будет работать только в приложениях на основе анализатора Microsoft (например: Internet Explorer использует его, а также .NET). Другие синтаксические анализаторы могут иметь или не иметь такого расширения (например, Saxxon, но он немного по-другому). Но он исключается в зависимости от XSLT 2.0, так как это отлично работает в XSLT 1.0, а Microsoft еще не поддерживает XSLT 2.0 в своей библиотеке XML (если только они не добавили ее в последнее время).

В зависимости от используемого парсера вышесказанное может работать нормально для вас, иначе Per T лучше для вас.

Ответ 3

В рабочем проекте XSLT 3.0 предлагается новый вид объекта (карты) XPath, см. карты в XSLT 3.0 WD Spec.

Итак, если ваш XSLT-процессор поддерживает 3.0 и карты (например, Saxon 9.4), вы можете использовать следующий код:

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

  <xsl:template match="/">
    <xsl:variable name="map" select="
      map { 
      'key-1' := 'value1', 
      'key-2' := 'value2',
      'key-3' := 'value3' }">      
    </xsl:variable>
    <output>
      <xsl:value-of select="
        $map('key-1') || ', ' || $map('key-2') || ', ' || $map('key-3')"/> 
    </output>
  </xsl:template>
</xsl:stylesheet>