2010-09-02 10 views
18

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

<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

Там немного о опечатка там происходит, является то, что и в документе? Это , который должен читать . – Rob

ответ

33

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() может извлекать значения карты. Ответ на similar question будет работать здесь :.

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

Как описано в XSLT 1.0 specification:

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

Для этого вам не нужно использовать xsl:variable. Вы можете указать свой узел карты непосредственно под 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> 
+0

Привет, Но тогда, когда я скопировал фрагмент дерева результатов, был напечатан правильно, и не только это даже значение только напечатало текстовые узлы в дереве результатов. BR, Keshav – keshav84

+0

@Keshav: Если вы используете только 'copy-of' /' value-of' в переменной '$ map', не пытаясь использовать его как набор узлов, он будет работать. Но как только вы попытаетесь сбить фрагмент результирующего дерева с выражением XPath, он потерпит неудачу. –

+0

Это почти * что мне нужно для моей конкретной проблемы. Что делать, если я хочу использовать xpath или параметр $ вместо жесткого ключа-1 для поиска правильной записи на карте? Я пробовал , но это не работает. – gilles27

5

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

Ваш 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 лучше для вас.

+0

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

+1

@ Ответ Per_T лучше во всех случаях, потому что это полностью * портативное * решение. Есть проблемы, которые очень трудно решить без расширения 'xxx: node-set()', но текущая проблема не является одной из них. Также, выступая за решение 'xxx: node-set()', всегда следует ссылаться на 'exslt: node-set()', что довольно переносимо, поскольку многие поставщики предоставляют EXSLT-реализации. –

+0

@ Dimitre Я должен признать, что ответ Пер Т дал мне некоторые вещи о XSL, которые я не знал (я не эксперт), поэтому я не знал намного лучше, и я определенно поддержал его ответ за то, что он отличный. ;) Я немного утверждаю, что, хотя переносимость - это очень хорошая вещь, ее важность зависит от контекста, поэтому я не хочу считать мой ответ довольно ужасным: это может сделать хорошо. ;) Это не сильно загрязняет ваш XSL, поскольку он не слишком инвазивен. Вот почему мы рады этому решению, даже если я согласен с вами в том, что это не идеально. :) Спасибо за ваш вклад! – Rob

3

В рабочем проекте XSLT 3.0 предлагается новый вид объекта (карты) XPath, см. maps in 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> 
Смежные вопросы