2010-09-02 17 views
18

Chcę mieć mapę wartości kluczy w xsl i tak zdefiniowałem zmienną, która ma fragment xml, ale później, gdy próbuję uzyskać dostęp do węzłów XML w zmiennej otrzymuję błąd tego typu Xpath Xpression nie może zostać rozwiązany.XSLT: Tworzenie mapy w 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

Jest trochę typo tam dzieje, jest to, że również w dokumencie? Jest to , który powinien przeczytać . – Rob

Odpowiedz

33

XSLT 2.0

Korzystanie XSLT 2.0, następujące rozwiązanie działa:

<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

Nie można używać drzewo wynik fragment w wyrażeniu XPath w XSLT 1.0, ale fn:document() może pobrać wartości mapy. Tutaj zadziała odpowiedź na similar question :.

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

Jak opisano XSLT 1.0 specification:

document('') odnosi się do węzła głównego arkusza stylów; drzewo reprezentacja arkusza stylów to dokładnie tak samo, jak dokument XML zawierający arkusz stylów to początkowy dokument źródłowy.

Do tego celu nie trzeba używać xsl:variable. Można określić węzeł map bezpośrednio pod xsl:stylesheet, ale trzeba pamiętać, że górne elementy poziom musi mieć non nazw zerowej 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

Witam, Cześć, Ale wtedy, gdy zrobiłem kopię - fragment drzewa wyników został wydrukowany prawidłowo, a nie tylko ta wartość - tylko wydrukowane węzły tekstowe w drzewie wyników. BR, BR, Keshav – keshav84

+0

@Keshav: Jeśli użyjesz tylko 'copy-of' /" value-of' na zmiennej '$ map' bez próby użycia jej jako zestawu węzłów, to zadziała. Ale gdy spróbujesz zejść w dół fragmentu drzewa wynikowego z wyrażeniem XPath, to się nie powiedzie. –

+0

To jest * prawie * to, czego potrzebuję dla mojego konkretnego problemu. Co zrobić, jeśli chcę użyć parametru xpath lub $ zamiast twardego klucza 1, aby wyszukać właściwy wpis na mapie? Próbowałem , ale to nie działa. – gilles27

5

można sortować prac wokół XSLT 1.0 brakującego wsparcie dla korzystania zawartość zmiennej jako zestaw węzłów. Będziesz musiał polegać na rozszerzeniach dodanych przez twórcę parsera. Na przykład, Microsoft zaoferował funkcję obejścia tego: node-set()

Twój XSL będzie wyglądać następująco:

<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> 

zauważy nazw i msxsl-prefix tutaj. Będzie działać tylko w aplikacjach opartych na parserze Microsoftu (na przykład: Internet Explorer go używa, a także .NET). Inne parsery mogą, ale nie muszą mieć takiego rozszerzenia (na przykład Saxxon, ale nazywa się to nieco inaczej). Ale eliminuje to w zależności od XSLT 2.0, ponieważ będzie to działało dobrze w XSLT 1.0, a Microsoft musi jeszcze obsługiwać XSLT 2.0 w swojej bibliotece XML (chyba, że ​​dodali ją ostatnio).

W zależności od używanego parsera powyższe może ci odpowiadać, w przeciwnym razie odpowiedź T-T jest dla ciebie lepsza.

+0

+1 Dobry dodatek do mojej odpowiedzi. Zwykle staram się unikać rozszerzeń specyficznych dla dostawcy, ale jest to zdecydowanie jeden sposób na rozwiązanie tego problemu! –

+1

@ Odpowiedź Per_T jest lepsza we wszystkich przypadkach, ponieważ jest to całkowicie * przenośne * rozwiązanie. Są to problemy bardzo trudne do rozwiązania bez rozszerzenia 'xxx: node-set()', ale obecny problem nie jest jednym z nich. Ponadto, zalecając rozwiązanie 'xxx: node-set()', zawsze powinieneś odwoływać się do 'exslt: node-set()', który jest dość przenośny, ponieważ wielu dostawców dostarcza implementacje EXSLT. –

+0

@Dimitre Muszę przyznać, że odpowiedź Per T nauczyła mnie pewnych rzeczy na temat XSL, których nie znałem (nie jestem ekspertem), więc nie wiedziałem o wiele lepiej i zdecydowanie przegłosowałem jego odpowiedź za bycie świetnym. ;) Twierdzę, że choć przenośność jest bardzo dobra, jej znaczenie zależy od kontekstu, więc nie chciałbym uważać mojej odpowiedzi za dość straszną: może to zrobić dobrze. ;) To naprawdę nie zanieczyszcza twojego XSL, ponieważ nie jest zbyt inwazyjny. Właśnie dlatego cieszymy się z tego rozwiązania, nawet jeśli się z tobą zgadzam, że nie jest doskonały. :) Dzięki za wkład! – Rob

3

W projekcie roboczym XSLT 3.0 zaproponowano nowy rodzaj elementu XPath (mapy), patrz maps in XSLT 3.0 WD Spec.

Dlatego, jeśli procesor XSLT obsługuje 3.0 i mapy (np Saxon 9.4), można użyć następującego kodu:

<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>