Parámetros y secuencias
Es importante mencionar la relación que existe entre parámetros y secuencias y el uso que se hace de ellos en las expresiones XPath. En esta documentación usamos los siguientes términos:
•Una secuencia está formada por componentes que son valores atómicos o nodos. Una coma sirve para construir una secuencia: poniendo una coma entre los componentes de una secuencia.
•La definición de una función XPath puede indicar que la función debe tomar parámetros. Por ejemplo, en la expresión XPath 2.0 count($a), la parte situada entre los paréntesis de la función es el parámetro de la función y debe ser una secuencia de componentes.
•En una llamada a función un argumento está formado por uno o varios componentes. Por ejemplo, la función count(//Person) tiene un argumento: //Person. Este argumento es válido porque devuelve una secuencia de nodos que equivale a la firma de la función count(). La firma de una función especifica el número de parámetros y el tipo de datos esperado de cada parámetro. También especifica qué devuelve la función y el tipo de datos del objeto devuelto.
•La función substring('StyleVisionExamples', 6, 6), que devuelve la cadena Vision, tiene tres argumentos. Según la firma de la función substring(), esto es válido. Cuando una llamada a función tiene varios argumentos, los argumentos se separan con comas.
Paréntesis como delimitador de secuencias
Hay algo muy importante que debe tener en cuenta cuando construya expresiones XPath: para delimitar secuencias que usen comas o el operador de intervalos se utilizan paréntesis. Como resultado, cada secuencia delimitada por paréntesis se lee como un solo parámetro (en las definiciones de función) o como un solo argumento (en las llamadas a función).
Los paréntesis no son obligatorios en una expresión de ruta (p. ej. //Person/@salary) porque las expresiones de ruta se pueden leer inequívocamente como un solo parámetro o argumento. De hecho, una expresión de ruta es un parámetro/argumento formado por una secuencia.
Estos ejemplos ilustran el punto anterior:
•avg((10, 20, 30))
La función XPath 2.0 avg toma una secuencia de componentes como único argumento. Como esta secuencia es una enumeración separada por comas, los paréntesis interiores son necesarios para delimitar la secuencia obligatoria. Sin los paréntesis interiores, la función tendría tres argumentos y, por tanto, no sería válida. Los paréntesis exteriores son los paréntesis de la función.
•avg(//Person/@salary)
Esta expresión de ruta selecciona los nodos de atributo salary de todos los elementos Person y devuelve sus valores en forma de secuencia que se debe evaluar (cuyo promedio se debe calcular). En este caso no hacen falta los paréntesis porque la secuencia no se enumera. El argumento es una sola expresión de ruta. La expresión de ruta se evalúa y los valores devueltos se suministran a la función como componentes de una secuencia.
•count((10 to 34))
Esta enumeración se consigue con el operador de intervalos. El operador de intervalos 'to' genera una secuencia de componentes separados por comas (los enteros comprendidos entre 10 y 34) antes de que se lea el argumento. Como resultado, la función count() tiene una secuencia de 25 componentes separados por comas dentro de su argumento. Para poder leer esta secuencia como un único argumento es necesario añadir los paréntesis. Sin estos paréntesis, la llamada a función tendría 25 argumentos en vez de uno y la llamada no sería válida porque la función count() solo puede tener un argumento, según su firma.
•count((10 to 34, 37))
Los paréntesis interiores señalan un argumento de la llamada a función: una sola secuencia formada por 26 componentes.
•count(//Person)
En este caso no hace falta poner el argumento entre paréntesis porque el argumento es una expresión de ruta que recopila los nodos //Person del documento XML y devuelve estos nodos como componentes de la secuencia que se debe contar.
Usar parámetros XPath en funciones XPath
Cuando use parámetros en la definición de una función XPath definida por el usuario, asegúrese de que (i) el número de argumentos de la llamada a esta función XPath es correcto y de que (ii) los argumentos dan como resultado el tipo de datos y las repeticiones indicadas en la definición de la función.
En el ejemplo de la imagen anterior se definieron tres parámetros, que se utilizan para definir la función XPath (en el panel Cuerpo de la función) .
Cada parámetro del panel Parámetros se considera una sola secuencia. El número de componentes permitidos dentro de cada secuencia se especifica con la propiedad Repeticiones. En la definición de la imagen anterior, por ejemplo, cada parámetro se definió como secuencia única (ver propiedad Repeticiones), es decir, una secuencia con exactamente un componente. Por tanto, cada argumento de la llamada a función debe tener una secuencia formada por exactamente un componente. La propiedad Tipo especifica el tipo de datos de los componentes de la secuencia.
En el ejemplo anterior, en la definición de función XPath (en el panel Cuerpo de la función) cada parámetro ofrece un componente de la secuencia cuyo promedio debe calcularse. Como el conjunto de parámetros XPath constituye una secuencia, estos deben ir entre paréntesis para garantizar toda la secuencia se lea como parámetro de la función avg(). Si en tiempo de ejecución alguno de los argumentos de la llamada a función (equivalentes a los tres parámetros) no es una secuencia única, se devuelve un error.
A continuación damos algunos ejemplos de expresiones XPath que llaman a la función XPath ThreeAverage(). En la vista Diseño puede insertar un cálculo automático y darle las expresiones XPath que aparecen a continuación para ver los resultados. La función toma una secuencia de tres enteros y calcula el promedio.
•sps:ThreeAverage(10,20,30) devuelve 20. Hay tres argumentos válidos en la llamada a función, que equivalen a los tres parámetros XPath.
•sps:ThreeAverage( (10),(20),(30) ) devuelve 20. Hay tres argumentos válidos en la llamada a función, que equivalen a los tres parámetros XPath. Cada argumento de entrada va entre paréntesis (lo cual es redundante porque cada secuencia es una secuencia única de todas maneras. Sin embargo, esta redundancia no constituye un error).
•sps:ThreeAverage( (10),20,30 ) devuelve 20. Hay tres argumentos válidos, que equivalen a los tres parámetros XPath. El primer argumento va entre paréntesis (lo cual es redundante pero no es un error).
•sps:ThreeAverage( (10,20),(30),(40) ) devuelve un error porque el primer argumento no es válido al ser no ser una secuencia única tal y como exige la definición del primer parámetro $a ('Exactamente una repetición').
•sps:ThreeAverage( (10,20,30) ) devuelve un error porque solamente se suministra un argumento entre paréntesis. Además el argumento no es válido porque no es una secuencia única.
Si la propiedad Repeticiones de un parámetro es Una como mínimo (imagen siguiente), entonces ese parámetro se define como secuencia compuesta por varios componentes.
En la definición de la imagen anterior, el primer parámetro se definió como una secuencia de varios componentes y los otros dos parámetros como secuencias únicas. La función definida cuenta el número de componentes suministrados por el primer parámetro, añade el resultado a la suma de los dos enteros dados por los otros dos parámetros y por último divide el resultado por tres para calcular el promedio. Observe que:
•El parámetro de la función avg() es una secuencia entre paréntesis. Esto especifica que la función avg() toma como parámetro una sola secuencia compuesta por tres componentes. La secuencia está formada por tres enteros: el primero es el suministrado por la función count() y el segundo y el tercero son los dados por los parámetros b y c.
•El argumento de la función count() no está entre paréntesis porque es inequívocamente una secuencia única.
A continuación damos dos ejemplos del uso de parámetros en llamadas a la función XPath Average() utilizada en el ejemplo.
•sps:Average((1,2),3,4) devuelve 3. Hay tres argumentos de entrada válidos en la llamada a función, que equivalen a los tres parámetros XPath. El primer argumento está entre paréntesis. Cuando la función count() se ejecuta en este argumento, la función devuelve el valor 2, que será el primer componente de la secuencia suministrada a la función avg().
•sps:Average( 4,4,4 ) devuelve 3. Hay tres argumentos de entrada válidos. El primer argumento puede ser una secuencia de un componente. No hace falta usar paréntesis para separar los argumentos.
Otros aspectos de importancia
Además debería tener en cuenta estos aspectos:
•Si definió un parámetro con una repetición de Una como mínimo, entonces puede definir una función como MyAverage() con una expresión XPath como avg(($a)). Esta función acepta un argumento que es una secuencia formada por varios componentes. Puede llamar a esta función de esta forma: sps:MyAverage((2,3,4)), lo cual devuelve el valor 3. El argumento de entrada debe ir entre paréntesis para garantizar que se lea como una sola secuencia y no como tres secuencias únicas.
•Si definió un parámetro $a con una repetición de Una o ninguna, entonces puede definir una función como MyAverage() con una expresión XPath como avg(($a, $b, $c)). Esta función acepta tres secuencias como argumento, con la posibilidad de que la primera secuencia esté vacía. Si la primera secuencia debe estar vacía, entonces debe enviar una secuencia vacía explícitamente como primer argumento de entrada. De lo contrario se emite un error. Si llamamos a la función así sps:MyAverage(30,20,10), devuelve el valor 20. Pero también se le puede llamar así sps:MyAverage((),20,10), lo cual devuelve el valor 15 (observe que la secuencia vacía cuenta como valor de entrada vacío. Para que el valor devuelto sea 10, el primer componente debería ser 0). Sin embargo, la llamada a función sps:MyAverage(20,10) devuelve un error porque no se suministró una primera secuencia vacía y, por tanto, se entiende que el tercer argumento de entrada está ausente.
Ejemplos complejos
Como decíamos, una gran ventaja de las funciones XPath definidas por el usuario es que se pueden usar en expresiones XPath del diseño SPS. Otra ventaja es que permiten construir funciones XPath complejas personales, no disponibles en el grupo de funciones de XPath 2.0. Por ejemplo, puede construir una función factorial con una expresión XPath que tome una secuencia única como único parámetro. Si el parámetro $num es el número que se debe factorizar, entonces la expresión XPath que crearía la función sería:
if ($num < 2) then 1 else $num * sps:Factorial($num - 1)
Si esta función se llamara Factorial(), entonces se podría obtener el factorial 6, por ejemplo, llamando a la función con sps:Factorial(6).