2008-12-10 17 views
5

Para una hoja de estilo que estoy escribiendo (en realidad para un conjunto de ellas, cada una generando un formato de salida diferente), tengo la necesidad de evaluar si un cierto valor está presente en una lista de valores. En este caso, el valor que se prueba se toma del atributo de un elemento. La lista que debe probarse proviene de la invocación de la hoja de estilo, y se toma como un nivel superior <xsl:param> (que se proporcionará en la línea de comandos cuando llamo al xsltproc o una invocación equivalente de Saxon). Por ejemplo, el valor de entrada puede ser:Prueba del elemento en lista

v0_01,v0_10,v0_99 

mientras que los valores de los atributos serán cada parecerse mucho a una dicho valor. (Si una coma se usa para separar valores, o un espacio, no es importante-- Elegí una coma por ahora porque planeo pasar el valor mediante el cambio de línea de comandos al xsltproc, y usar un espacio requeriría citar el argumento, y soy lo suficientemente flojo como para no querer escribir los dos caracteres adicionales.)

Lo que estoy buscando es algo parecido al grep de Perl, donde puedo ver si el valor que tengo actualmente está en la lista. Se puede hacer con pruebas de subcadena, pero esto debería ser inteligente para no obtener un falso positivo (v0_01 no debería coincidir con una cadena que contiene v0_011). Parece que el único tipo de datos no escalar que admite XSL/XSLT es un conjunto de nodos. Supongo que es posible convertir la lista en un conjunto de nodos de texto, pero eso parece exagerar, incluso en comparación con hacer una prueba de subcadena con controles de límites adicionales para evitar coincidencias falsas.

Respuesta

8

En realidad, usar las funciones de cadena XPath es la forma correcta de hacerlo. Todo lo que tiene que asegurarse es que también pruebe los delimitadores:

contains(concat(',' $list, ','), concat(',', $value, ',')) 

devolvería un valor booleano. O puede ser que utilice uno de estos:

substring-before(concat('|,' $list, ',|'), concat(',', $value, ',')) 

o

substring-after(concat('|,' $list, ',|'), concat(',', $value, ',')) 

Si obtiene una cadena vacía como el resultado, $value no está en la lista.

EDIT:

@ comentario de Dimitre es correcta: substring-before() (o substring-after()) también devolvería la cadena vacía si la cadena encontrada es el primer (o el último) en la lista. Para evitar eso, agregué algo al principio y al final de la lista. Todavía es la forma recomendada de hacer esto.

+0

En realidad, para mis propósitos, parece que funcionará la función "contiene" (usando el relleno que sugiera). Lo que me hizo tropezar, fue que estaba buscando esta funcionalidad dentro de XSLT, cuando debería haber estado buscando en XPath. – rjray

+0

Agregué la función contains(), esa me había escapado. Gracias. :-) – Tomalak

+0

@Tomalak: La expresión substring-before() evaluará a '' incluso si el valor está en la lista (cuando es el primer valor). De forma similar, la expresión substring-after() evalúa '' cuando el valor es el último en la lista. Por lo tanto, solo la expresión contains() es correcta –

4

Además de la solución XPath 1.0 proporcionado por Tomalak,

Usando XPath 2.0 uno puede tokenize la lista de valores:

        exists(tokenize($list, ',')[. = $value])

evalúa a true() si y sólo si $value figura en la lista de valores $list

+0

¿No es mejor escribir de esta manera: tokenize ($ list, ',') = $ value – lagivan

+1

@lagivan, depende de lo que comprendamos mejor. Creo que usar "existe" (como palabra o concepto) es inmediatamente más comprensible y natural para las personas que no están acostumbradas a los accesos directos de XPath. Además, la función "exists()" podría optimizarse mejor que una comparación de valores generales. –

Cuestiones relacionadas