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>
Ответы
Ответ 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>