2010-09-02 16 views
18

Quiero tener un mapa de valores clave en xsl y así definí una variable que tiene un fragmento xml, pero más tarde cuando trato de acceder a los nodos xml en la variable me sale un error de ese tipo de xpath xpression no se puede resolver.XSLT: Creando un Mapa en 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

Hay un poco de un error tipográfico pasando allí, es que también en su documento? Es que debería leer . – Rob

Respuesta

33

XSLT 2.0

mediante XSLT 2.0, la siguiente solución funciona:

<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

No puede utilizar un fragmento de árbol de resultados en una expresión XPath en XSLT 1.0, pero fn:document() puede recuperar valores del mapa. Una respuesta a similar question funcionará aquí:

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

Como se describe en la XSLT 1.0 specification:

document('') se refiere al nodo raíz de la hoja de estilo; el árbol representación de la hoja de estilo es exactamente igual que si el documento XML que contiene la hoja de estilo fuera el documento fuente inicial.

Sin embargo, no necesita utilizar xsl:variable para esto. Se podría especificar su nodo del mapa directamente bajo xsl:stylesheet, pero hay que recordar que una serie de elementos de nivel superior deben tener un espacio de nombres no nula 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

Hola, Pero cuando hice una copia del resultado, el fragmento de árbol se imprimió correctamente y no solo ese valor par, solo imprimí los nodos de texto en el árbol de resultados. BR, Keshav – keshav84

+0

@Keshav: Si solo usa 'copy-of' /' value-of' en la variable '$ map' sin tratar de usarlo como un conjunto de nodos, funcionará. Pero una vez que intentes avanzar por el fragmento del árbol de resultados con una expresión XPath, fallará. –

+0

Esto es * casi * lo que necesito para mi problema particular. ¿Qué ocurre si quiero usar un xpath o un parámetro $ en lugar de la clave 1 cableada para buscar la entrada correcta en el mapa? He intentado pero eso no funciona. – gilles27

5

se puede ordenar de trabajo alrededor de XSLT 1.0 soporte para utilizar el contenido de la variable como falta un conjunto de nodos Tendrá que confiar en las extensiones agregadas por el creador del analizador. Por ejemplo, Microsoft ha ofrecido una función para evitar este: conjunto de nodos()

Su XSL se verá así:

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

Aviso el espacio de nombres y la msxsl-prefix aquí. Esto solo funcionará en aplicaciones basadas en el analizador de Microsoft (por ejemplo: Internet Explorer lo utiliza, así como .NET). Otros analizadores sintácticos pueden o no tener dicha extensión (por ejemplo, Saxxon, pero su nombre es un poco diferente). Pero, elimina según XSLT 2.0, ya que funcionará bien en XSLT 1.0 y Microsoft aún no ha sido compatible con XSLT 2.0 en su biblioteca XML (a menos que lo hayan agregado recientemente).

Dependiendo del analizador que esté utilizando, lo anterior puede funcionar bien para usted, de lo contrario la respuesta de Per T es mejor para usted.

+0

+1 Buena adición a mi respuesta. Usualmente trato de evitar las extensiones específicas del proveedor, ¡pero definitivamente es una forma de resolverlo! –

+1

@ La respuesta de Per_T es mejor en todos los casos, porque es una solución completamente * portátil *. Hay problemas que son muy difíciles de resolver sin la extensión 'xxx: node-set()', pero el problema actual no es uno de estos. Además, al abogar por una solución 'xxx: node-set()' uno siempre debe referirse al 'exslt: node-set()', que es bastante portátil porque muchos proveedores proporcionan implementaciones EXSLT. –

+0

@Dimitre Debo admitir que la respuesta de Per T me ha enseñado algunas cosas sobre XSL que yo no sabía (no soy un experto), por lo que no sabía mucho mejor y definitivamente elevé su respuesta por ser excelente. ;) Discuto un poco que, aunque la portabilidad es algo muy bueno, su importancia depende del contexto, por lo que no querría considerar mi respuesta como algo terrible: podría funcionar bien. ;) Realmente no contamina su XSL tanto como no es demasiado invasivo. Es por eso que estamos contentos con esta solución, incluso si estoy de acuerdo con usted en que no es perfecta. :) ¡Gracias por tu contribución! – Rob

3

En XSLT 3.0 Borrador de trabajo, se propone un nuevo tipo de elemento XPath (mapa), consulte maps in XSLT 3.0 WD Spec.

tanto, si su procesador XSLT es compatible con 3.0 y mapas (por ejemplo sajones 9.4), puede utilizar el siguiente código:

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