[1] | Module | ::= | VersionDecl? (MainModule | LibraryModule) |
[3] | MainModule | ::= | Prolog QueryBody |
[4] | LibraryModule | ::= | ModuleDecl Prolog |
[6] | Prolog | ::= | (Setter Separator)* ((Import | NamespaceDecl | VarDecl | FunctionDecl) Separator)* |
[7] | Setter | ::= | XMLSpaceDecl | DefaultCollationDecl | BaseURIDecl | ConstructionDecl | DefaultNamespaceDecl | DefaultOrderingDecl |
[8] | Import | ::= | SchemaImport | ModuleImport |
[9] | Separator | ::= | ";" |
[25] | QueryBody | ::= | Expr |
[定义:一个查询可以由一个或多个称为
模块(
modules)的片断装配而成。每个模块是一个主模块(main module)或者库模块(library module)。]每个模块依次由一个或多个称为模块资源(module resources)的部分组成。[定义:每个
模块资源(
module resource)是一段XQuery代码,符合模块(Module)语法并且能独立地经过
2.2.3 Expression Processing中说明的静态分析阶段(static analysis phase)。]
[定义:一个
主模块(
main module)由包含一个序言(Prolog)及其后的一个查询体(Query Body)的单个模块资源构成。] 一个查询有一个确定的主模块。在一个主模块中,查询体(Query Body)能被计算,其值是查询的结果。
[定义:不包含查询体(Query Body)的模块称为库模块(
library module)。] 一个库模块可能由多个模块资源(module resources)组成,每个模块资源包含一个模块声明(module declaration)及其后的序言(Prolog)。多个模块资源如果在其模块声明中命名同样的目标名字空间(target namespace),则被被视为同一库模块的部分。一个库模块不能直接被计算;相反的,它提供可以被导入到其他模块的函数和变量声明。
没有模块资源(module resource)能既包含模块声明(module declaration)又包含查询体(Query Body)。
[定义:
序言(
Prolog)是一连串的声明和导入,为包含序言的模块资源(module resource)定义处理环境] 每个声明或者导入跟着一个分号。[定义:序言中的某些声明称为
给定器(
setters),因为他们设置某些影响查询处理的性质的值,例如构造模式、排序模式、或者缺省校对。] 这些给定器如果存在,必须出现在序言的开始,以任何次序。一个序言也可以包含模式和模块导入,和名字空间前缀、变量和函数的声明。 [定义:每个导入模式或模块由其
目标命名空间(
target namespace)识别, 就是由模式或模块定义的对象(如元素或函数)的命名空间。]
[定义:
查询体(
Query Body)如果存在,由一个规定查询结果的表达式组成。] 表达式的计算在中
3 Expressions说明。一个模块只有当它有查询体时才被计算。
4.1 版本声明 Version Declaration[2] | VersionDecl | ::= | "xquery" "version" StringLiteral Separator |
[定义:任意模块资源(module resource)可以包含一个
版本声明(
version declaration)。如果存在,版本声明出现在模块资源(module resource)的开始,且为模块资源(module resource)识别可用的XQuery语法和语义。] 版本号“1.0”表明模块资源(module resource)必须由一个XQuery版本1.0处理器来处理的需求。如果版本声明不存在,则版本被假设为“1.0”。当一个XQuery实现处理一个用其不支持的版本标志的模块资源(module resource)时,必须返回一个静态错误(static error)。[err:XQ0031] XQuery工作组这样做的意图是给出这个规范数字不同于“1.0”的随后的版本,但是这个意图不表明承诺提出任何XQuery的未来版本,如果提出来也不一定使用任一特定的数字模式。
下面是一个版本声明的例子:
xquery version "1.0";
4.2 模块声明 Module Declaration[5] | ModuleDecl | ::= | "module" "namespace" NCName "=" StringLiteral Separator |
[定义:
模块声明(
module declaration)用于标识一个模块资源(module resource)为一个库模块(library module)的一部分。一个模块声明由关键字module及其后一个命名空间前缀和一个包含合法的URI的串文字组成。[err:XQ0046]] URI标识库模块的目标命名空间(target namespace),这是由这个库文件导入的所有变量和函数的命名空间。库模块中声明的每一个变量和函数的名字必须有一个与模块的目标命名空间同样的命名空间URI。[err:XQ0048]
任意一个模块资源(module resource)都可以以模块导入(module import)的方式导入一个库模块,模块导入(module import)指定要导入的库模块的目标命名空间。当一个模块导入一或多个库模块时,被导入模块的变量和函数声明将加到此模块的静态语境(static context)和(如果可用)动态语境(dynamic context)中。
下面是一个模块声明的例子:
module namespace math = "http://example.org/math-functions";
4.3 Xmlspace 声明 Xmlspace Declaration[11] | XMLSpaceDecl | ::= | "declare" "xmlspace" ("preserve" | "strip") |
[定义:序言(Prolog)中的
xmlspace 声明(
xmlspace declaration)控制边界空格(boundary whitespace)是否被直接元素构造器(direct element constructors)在查询执行时保留。] 如果指定xmlspace preserve,则边界空格被保留。如果指定xmlspace strip或者不存在xmlspace声明,边界空格被去除(删除)。构造元素中空格的进一步说明可以在
3.7.1.4 Whitespace in Element Content中找到。
下面是一个xmlspace声明的例子:
declare xmlspace preserve;
4.4 缺省校对声明 Default Collation Declaration[14] | DefaultCollationDecl | ::= | "declare" "default" "collation" StringLiteral |
序言(Prolog)会声明一个缺省校对(default collation),这是如果没有其他指定校对时,要求校对的函数和操作符使用的校对的名字。例如,作用于字符串的操作符gt由调用函数fn:compare来定义,其带有可选的校对参数。既然操作符gt没有指定一个校对,函数fn:compare使用在序言中指定的缺省校对执行。缺省校对通过一个必须包含一个合法URI的文字串识别。[err:XQ0046]
如果一个序言没有指定缺省校对,则使用Unicode codepoint collation (http://www.w3.org/2004/07/xpath-functions/collation/codepoint)除非实现提供一个不同的缺省校对。
下面是一个缺省校对声明的例子:
declare default collation
"http://example.org/languages/Icelandic";
如果一个序言指定一个以上的缺省声明,或者指定值不能被一个实现识别为已知校对,将引发一个静态错误(static error)。[err:XQ0038]
4.5 基 URI 声明 Base URI Declaration[15] | BaseURIDecl | ::= | "declare" "base-uri" StringLiteral |
(
base URI declaration)指定静态语境的
基 URI(
base URI)性质,在解析模块资源(module resource)内的相对URI时被使用。如果一个序言(Prolog)中发现一个以上的基URI声明,将引发一个静态错误(static error)[err:XQ0032]。 如果一个基URI声明中的串文字不包含一个合法URI,将引发一个静态错误(static error)[err:XQ0046]。注意,函数fn:doc使用调用模块的基URI解析相对URI。
下面是一个基URI声明的例子:
declare base-uri "http://example.org";
4.6 构造声明 Construction Declaration[20] | ConstructionDecl | ::= | "declare" "construction" ("preserve" | "strip") |
序言(Prolog)中的
构造声明(
construction declaration)设置静态语境(static context)中的构造模式(construction mode)为preserve或strip。构造模式支配元素构造器的行为。如果构造模式为preserve,则一个构造元素节点为xs:anyType,而且这个构造元素节点的属性和子孙节点保持其原来的类型。如果构造模式为strip,构造元素节点及其所有子节点的类型为xdt:untyped, 构造元素的属性类型为xdt:untypedAtomic. 元素构造器在
3.7.1 Direct Element Constructors和
3.7.3.1 Computed Element Constructors中说明。
下例说明一个构造声明:
declare construction strip;
如果一个序言指定多于一个构造声明,将会引发一个静态错误(static error) [err:XQ0067]
4.7 缺省命名空间声明 Default Namespace Declaration[12] | DefaultNamespaceDecl | ::= | (("declare" "default" "element") | ("declare" "default" "function")) "namespace" StringLiteral |
用在序言(Prolog)中,来使没有前缀的QName便于使用。在缺省命名空间声明中使用的串文字必须是一个合法的URI或者一个零长串。[err:XQ0046] 下列种类的缺省命名空间声明是支持的:
- 缺省元素 / 类型命名空间声明 ( default element/type namespace declaration )声明一个与无前缀的元素和类型名关联的命名空间URI。此声明在静态语境(static context)中记录为缺省元素/类型命名空间(default element/type namespace)。一个序言(Prolog)最多只可以包含一个缺省元素/类型命名空间声明。[err:XQ0066] 如果缺省元素/类型命名空间声明中的串文字(StringLiteral)是一个零长串,缺省元素/类型命名空间(default element/type namespace)被设为“none,”且元素和类型的无前缀名字被认为不在命名空间中。下面的例子说明一个缺省元素/类型命名空间的声明:
· declare default element namespace "http://example.org/names";
缺省元素/类型命名空间声明可能被直接元素构造器(direct element constructor)中的命名空间声明属性(namespace declaration attribute)或者计算元素构造器(computed element constructor)中的本地命名空间声明(local namespace declaration)重载。
- 缺省函数命名空间声明 ( default function namespace declaration )声明一个与函数调用中的无前缀函数名相关联的命名空间URI。 此声明在静态语境(static context)中记录为缺省函数命名空间(default function namespace)。一个序言(Prolog)最多只可以包含一个缺省函数命名空间声明 [err:XQ0066] 。 如果一个缺省函数命名空间声明中串文字(StringLiteral)为一零长串,将引发一个静态错误 [err:XQ0063] 。 如果没有声明缺省函数命名空间,则缺省函数命名空间为XPath/XQuery函数的命名空间,http://www.w3.org/2004/07/xpath-functions (然而,这个缺省值可能被一个实现重载。)下面的例子说明缺省函数命名空间的声明:
· declare default function namespace
· "http://example.org/math-functions";
声明一个缺省函数命名空间的效果是,缺省函数命名空间中包括隐含声明的构造函数在内的所有函数,都以具有原来的本地名但是没有命名空间URI的名字为别名。于是函数可以用其原来的名字或者它的别名调用——就是说,命名空间前缀成为可选项。当一个函数调用使用一个没有前缀的函数名时,这个函数的本地名必须和一个在缺省函数命名空间中的函数(包括隐含声明的构造函数)相匹配。[err:XP0017]
无前缀属性名和变量名不属于命名空间。
4.8 缺省排序声明 Default Ordering Declaration[13] | DefaultOrderingDecl | ::= | "declare" "ordering" ("ordered" | "unordered") |
[定义:
缺省排序声明(
default ordering declaration)设置静态语境(static context)中的排序模式(ordering mode)。] 这个排序模式应用于一个模块资源(module resource)(包括序言(Prolog)和查询体(Query Body),如果有的话)中的所有表达式,除非被一个ordered 或 unordered表达式重载。如果一个序言(Prolog)中发现多于一个的缺省排序声明,将引发一个静态错误(static error)[err:XQ0065].
排序模式(Ordering mode)影响没有order by子句的路径表达式、union、intersect和、except表达式和FLWOR表达式的行为。如果排序模式为ordered,由路径、union、intersect和、except表达式返回的节点序列为文档顺序(document order);否则,这些返回序列的次序为依赖实现的(implementation-dependent)。排序模式对FLWOR表达式的影响在
3.8 FLWOR Expressions中说明。
下例说明一个缺省排序声明:
declare ordering unordered;
4.9 模式导入 Schema Import[16] | SchemaImport | ::= | "import" "schema" SchemaPrefix? StringLiteral (("at" StringLiteral) ("," StringLiteral)*)? |
[17] | SchemaPrefix | ::= | ("namespace" NCName "=") | ("default" "element" "namespace") |
[定义:
模式导入(
schema import)把元素、属性和类型定义从模式导入到模式定义作用域(in-scope schema definitions)中。] 将被导入的模式由其目标命名空间(target namespace)标识。模式导入会给已导入模式绑定一个命名空间前缀,或者会声明目标命名空间为缺省元素/类型命名空间(default element/type namespace)模式导入也会为模式的定位提供可选提示。
一个模式导入中的串文字必须是合法的URI。 [err:XQ0046] 这些串文字的开始指定了将要导入的模式的目标命名空间。接在关键字后面的串文字是可选的位置提示,可以以依赖实现的方式被解释或者不予处理。多个位置提示被用来指示多于一个的可能位置,来寻找模式或者多个组成模式的实际资源。
指定一个零长串为目标命名空间的模式导入,被认为是导入一个没有命名空间的模式。这样的模式导入可以不必绑定一个命名空间前缀 [err:XQ0057],但是它会设置缺省元素/类型命名空间为“no namespace”,允许导入的名字空间中的定义被引用。如果缺省元素/类型命名空间没有设置为“no namespace”,就没有办法引用没有目标命名空间的导入模式中的定义。
如果同一个序言(Prolog)中多于一个的模式导入指定同一个目标命名空间,将引发静态(static error)错误。[err:XQ0058] 如果实现不能通过查找一个具有指定目标命名空间的合法的模式处理一个模式导入,将引发静态错误(static error)[err:XQ0059]。如果多个导入的模式或者多个同一模式内的实际资源,包含对相同符号空间(例如,对同样的元素名的两个定义,甚至是一致的定义)中相同名字的定义,将引发一个静态错误(static error)[err:XQ0035]。然而,以目标命名空间http://www.w3.org/2001/XMLSchema(预定义前缀xs)导入的模式,不产生错误,即使这个模式中定义的内部类型隐含的包括在类型定义作用域(in-scope type definitions)中。
下面的例子为一个XHTML文档导入模式,指定其目标命名空间及其位置,并绑定前缀xhtml到此命名空间:
import schema namespace xhtml="http://www.w3.org/1999/xhtml"
at "http://example.org/xhtml/xhtml.xsd";
下面的例子通过仅仅指定其目标命名空间导入一个模式,并使其成为默认元素/类型命名空间:
import schema default element namespace "http://example.org/abc";
下面的例子导入一个没有目标命名空间的模式,提供一个位置提示,并设置缺省元素/类型命名空间为“no namespace”以便导入模式中的定义可以被引用:
import schema default element namespace ""
at "http://example.org/xyz.xsd";
下面的例子导入一个没有目标命名空间的模式,并设置缺省元素/类型命名空间为“no namespace”。由于没有提供位置提示,它可用于实现来查找被导入的模式。
import schema default element namespace "";
4.10 模块导入 Module Import[18] | ModuleImport | ::= | "import" "module" ("namespace" NCName "=")? StringLiteral (("at" StringLiteral) ("," StringLiteral)*)? |
[定义:
模块导入(
module import)从一个库模块(library module)导入函数声明和变量声明到被导入模块资源(module resource)的函数签名(function signatures)和变量作用域(in-scope variables)中。] 要被导入的模块由其目标命名空间(target namespace)确定。模块导入会把一个命名空间前缀与被导入模块的目标命名空间绑定,而且它会为定位被导入模块的模块资源(module resources)提供可选的提示。
一个模块导入中的串文字必须是合法的URI。[err:XQ0046] 这些串文字的开始指定了被导入模块的目标命名空间。在关键字后面的串文字为可选的定位提示,能够以一种实现定义(implementation-defined)的方式被解释或者不予处理。如果被导入模块由多个模块资源(module resources)组成,这些模块资源中的所有函数和变量声明都将被导入。
如果在一个序言(Prolog)中有多于一个的模块导入指定同一个目标命名空间,将引发一个静态错误(static error)[err:XQ0047]。如果被导入模块和导入模块的目标命名空间相同,将引发一个静态错误[err:XQ0056] 。如果实现不能通过查找一个由指定目标命名空间定义的合法模块,来处理一个模块导入,将引发静态错误(static error)[err:XQ0059]。如果多个被导入模块或者一个被导入模块内的多个模块资源(module resources),包含对同一符号空间(例如,同一函数的两个定义,甚至是一致的定义)的同一名字的定义,将引发一个静态错误(static error)[err:XQ0034][err:XQ0049]。
每个模块资源(module resource)有其自身的静态语境(static context)。一个模块导入(module import)仅导入函数和变量声明;不从被导入模块中导入其他对象,比如其模式定义作用域(in-scope schema definitions)或者静态已知命名空间(statically known namespaces)。模块导入不可传递——就是说,导入一个模块只提供对直接包含在被导入模块中的函数及变量声明的访问。例如,如果模块A导入模块B,并且模块B导入模块C,模块A没有访问C中声明的函数和变量的权力。两个模块可以互相导入。
如果导入模块的类型定义作用域(in-scope type definitions)不包括被导入模块中出现的变量声明、函数参数或函数返回值的类型名的定义,这样的模块导入会引发一个类型错误(type error)[err:XQ0036]。导入一个包含其名字已经在导入模块的静态语境中声明过的函数声明或者变量声明的模块,是一个静态错误(static error)[err:XQ0037]。
为了说明上述规则,假定某一个模式定义了一个类型名triangle。假定一个库模块导入此模式,将其目标命名空间与前缀geometry绑定,并用下面的函数签名(function signature)声明了一个函数:math:area($t as geoetry:triangle) as xs:double。如果查询希望使用这个函数,它必须既导入库模块,又导入库文件基于的模式。仅仅导入库模块不提供对在函数area的签名中使用的geometry:triangle类型定义的访问。
下面的例子说明一个模块导入:
import module namespace math = "http://example.org/math-functions";
4.11 命名空间声明 Namespace Declaration[10] | NamespaceDecl | ::= | "declare" "namespace" NCName "=" StringLiteral |
[定义:
命名空间声明(
namespace declaration)说明一个命名空间前缀并将其与一个命名空间URI关联,添加(前缀,URI)对到静态已知命名空间(statically known namespaces)集合中。] 在命名空间声明中使用的串文本必须是一个合法的URI [err:XQ0046] 或者一个零长串。命名空间声明的作用域贯穿其声明的整个查询,除非它被一个直接元素构造器(direct element constructor)中的命名空间声明属性(namespace declaration attribute)或者一个计算元素构造器(computed element constructor)中的本地命名空间声明(local namespace declaration)所重载。
下面的查询说明一个命名空间声明:
declare namespace foo = "http://example.org";
<foo:bar> Lentils </foo:bar>
在查询结果中,新创建的节点是在与命名空间URI http://example.org相关联的命名空间中的。
一个序言(Prolog)中的同一个命名空间前缀的多个声明,导致一个静态错误(static error)[err:XQ0033]。然而,一个序言中的一个命名空间的声明,能重载一个已经在静态语境中声明过的前缀。
使用一个有一个已经被声明过的命名空间前缀的QName,将引发一个静态错误(static error)。[err:XP0008]
XQuery有几个预声明的命名空间前缀,它们于每个查询被处理前,在静态已知命名空间(statically known namespaces)中给出。这些前缀可以在没有显式声明的情况下使用。它们会被序言(Prolog)中的命名空间声明(namespace declarations)所重载,或者被关于构造元素的命名空间属性(namespace declaration attributes)或本地命名空间声明(local namespace declarations)所重载(除了前缀xml,它可以不必重新声明)。预声明的命名空间前缀如下:
- xml = http://www.w3.org/XML/1998/namespace
- xs = http://www.w3.org/2001/XMLSchema
- xsi = http://www.w3.org/2001/XMLSchema-instance
- fn = http://www.w3.org/2004/07/xpath-functions
- xdt = http://www.w3.org/2004/07/xpath-datatypes
- local = http://www.w3.org/2004/07/xquery-local-functions (参见 4.13 Function Declaration .)
附加的预定义命名空间前缀可以由实现加到静态已知命名空间(statically known namespaces)。
命名空间前缀也有一个特殊的意义(它标识一个命名空间声明属性(namespace declaration attribute)),并且它不可以被重新声明。
如果一个命名空间声明的串文字部分为一零长串,则应用下列规则:
- 如果实现支持 [XML Names 1.1] ,任何现有的为给定前缀绑定的命名空间从静态已知命名空间(statically known namespaces)中删除。这个特性提供了一个方式,来删除象local这样的预声明命名空间前缀。
- 如果实现不支持 [XML Names 1.1],引发一个静态错误。[err:XQ0053]
- 一个特定的实现是否支持[XML Names 1.1],是由实现定义的。
当元素或者属性名相比较时,如果它们的本地部分和命名空间URI在码点基础上匹配,则认为相同。两个名字的匹配不必命名空间前缀相同,如下例所示:
declare namespace xx = "http://example.org";
let $i := <foo:bar xmlns:foo = "http://example.org">
<foo:bing> Lentils </foo:bing>
</foo:bar>
return $i/xx:bing
尽管命名空间前缀xx和foo不同,但都与命名空间URI“http://example.org”绑定。因为xx:bing和foo:bing有相同的本地名和相同的命名空间URI,他们相匹配。上述查询的输出如下:
<foo:bing> Lentils </foo:bing>
4.12 变量声明 Variable Declaration[19] | VarDecl | ::= | "declare" "variable" "$" VarName TypeDeclaration? ((":=" ExprSingle) | "external") |
[136] | VarName | ::= | QName |
[109] | TypeDeclaration | ::= | "as" SequenceType |
变量声明(
variable declaration)添加一个变量的静态类型到变量作用域(in-scope variables)中,也可以为变量添加一个值到变量值(variable values)。如果变量作用域(in-scope variables)中变量的扩展QName(expanded QName)和另一个变量的相同,将引发一个静态错误(static error)[err:XQ0049]。
如果变量声明包含一个类型,那个类型和变量类型一样被添加到静态语境中。如果变量声明中包含一个不是显式类型的表达式,变量的静态类型将通过表达式的静态类型来推断。如果一个变量声明既包含一个类型又包括一个表达式,表达式的静态类型必须与已声明的静态声明兼容;否则将引发一个类型错误[err:XP0004]。
[定义:如果一个变量声明包含一个表达式,这个表达式称为
初始化表达式(
initializing expression)。] 一个给定变量的初始化表达式必须在任何一个引用此变量的表达式求值之前被求值。一个初始化表达式的静态语境(static context)包括所有在序言(Prolog)中任何位置声明或导入的函数,但是它只包括那些在序言中声明或导入的比将要被初始化的变量早的变量和命名空间。如果一个初始化表达式由于一个环(例如,它依赖的函数转过来依赖于将要被初始化的变量的值)而不能被求值,将引发一个静态错误(static error)[err:XQ0054]。
如果变量声明包含关键字external,则在查询能被求值之前,外部环境必须为变量提供一个值。如果外部变量声明也包含一个声明的类型,则由外部环境声明提供的值必须与声明的类型一致,此处应用
2.4.4 SequenceType Matching中的匹配规则(参见
2.2.5 Consistency Constraints)。如果一个外部变量声明不包含一个已声明类型,类型和匹配的值必须由外部环境在求值时提供。这样的变量的静态类型被认为是item()*。
在一个库模块(library module)中声明的所有变量名必须(当已扩展时)在这个库模块的目标命名空间(target namespace)中。[err:XQ0048] 当一个库模块被导入时,被导入模块的变量声明被添加到导入模块的变量作用域(in-scope variables)中。
没有命名空间的变量名不在命名空间中。没有命名空间前缀的变量声明只能出现在主模块中。
术语
变量声明(
variable declaration)总是指序言(Prolog)中一个变量的声明。将一个变量绑定到一个查询表达式(如FLWOR表达式)中的值,称为
变量绑定(
variable binding)并不使得变量对导入模块可见。
这是变量声明的例子:
- 下面的声明同时指定一个变量的类型和值。这个声明使得类型xs:integer与变量$x在静态语境(static context)中关联,使得值7与变量$x在动态语境(dynamic context)中关联。
· declare variable $x as xs:integer := 7;
- 下面的声明指定一个值,但是不指定类型。变量的静态类型从其值的静态类型上推断。这种情况下,从值7.5上推断出变量$x的静态类型为xs:decimal。
· declare variable $x := 7.5;
- 下面的声明指定了类型但是没有指定值。关键字external 说明变量的值将由外部环境提供。在求值时,如果动态语境(dynamic context)中的变量没有类型为xs:integer的值,将引发一个类型错误。
· declare variable $x as xs:integer external;
- 下面的声明既没有指定类型,也没有指定值。它仅仅声明了查询依赖于名为$x的变量的存在,此变量的类型和值将由外部环境提供。在查询分析期间,的类型被认为是。在查询求值期间,动态语境(dynamic context)必须包含$x的类型和值,并且其类型和值必须一致。
· declare variable $x external;
4.13 函数声明 Function Declaration除了在[XQuery 1.0 and XPath 2.0 Functions and Operators]中说明的内置函数之外,XQuery允许用户声明他们自己的函数。函数声明指定函数的名字、参数的名字和数据类型、以及结果的数据类型。所有的数据类型使用
2.4 Types中描述的语法指定。函数声明使被声明的函数被添加到它出现的模块资源(module resource)的函数签名(function signatures)中。
[21] | FunctionDecl | ::= | "declare" "function" QName "(" ParamList? (")" | (")" "as" SequenceType)) (EnclosedExpr | "external") |
[22] | ParamList | ::= | Param ("," Param)* |
[23] | Param | ::= | "$" VarName TypeDeclaration? |
[109] | TypeDeclaration | ::= | "as" SequenceType |
函数声明确定一个函数是用户定义函数(user-defined)还是外部函数(external)。 [定义:对于一个
用户定义函数(
user-defined function)来说,函数声明包括一个称为
函数体(
function body)的表达式,它定义函数结果如何从函数的参数计算得到。] 一个函数体的静态语境(static context)包括在序言(Prolog)任何地方被声明或者导入的所有函数,但是它只包括在序言中声明或者导入的比函数定义早的变量和命名空间。
[定义:
外部函数(
External functions)是在查询环境外部被实现的函数。] 例如,除了在[XQuery 1.0 and XPath 2.0 Functions and Operators]中说明的核心函数库以外,一个XQuery实现会提供一组外部函数。外部函数通过关键字external来识别。一个外部函数的函数声明的目的,是声明函数参数和结果的数据类型,以便于包含或者导入这个函数声明的查询在类型检查时使用。
一个XQuery实现可能提供一个功能,借此,外部函数能够用一个宿主程序设计语言(host programming language)实现,但这不是必需的。如果提供了这样的功能,参数传递到一个外部函数、函数结果返回到调用查询所使用的协议是实现定义的(implementation-defined)。
一个XQuery实现可能用附加的类型来扩充[XQuery 1.0 and XPath 2.0 Data Model]的类型系统,设计附加的类型易于同宿主程序设计语言交换数据,它也可以为用户提供定义这样类型的机制。例如,可以提供一个类型,它封装一个由外部函数返回的,象一个SQL数据连接那样的对象。这些附加类型(如果定义了)被认为是由约束从xdt:anyAtomicType派生的。
每个函数必须在一个命名空间中——就是说,每个被声明的函数名必须(扩展时)有个一非空的命名空间URI[err:XQ0060]。每一个在库模块(library module)中声明的函数名必须(扩展时)在一个库模块的目标命名空间(target namespace)中[err:XQ0048]。如果函数声明中的函数名(在扩展时)不在下列任意一个命名空间中,将引发一个静态错误(static error)[err:XQ0045]:
- http://www.w3.org/XML/1998/namespace
- http://www.w3.org/2001/XMLSchema
- http://www.w3.org/2001/XMLSchema-instance
- http://www.w3.org/2004/07/xpath-functions
- http://www.w3.org/2004/07/xpath-datatypes
如果声明的函数的扩展QName(expanded QName)和参数数目,与函数签名中的另一个函数的扩展QName(expanded QName)和参数数目相同,将引发一个静态错误 [err:XQ0034]。
为了允许主模块在不定义一个新的命名空间的情况下,为模块内本地使用声明函数,XQuery预定义了到命名空间http://www.w3.org/2004/07/xquery-local-functions的命名空间前缀local,并为定义本地函数使用保留这个命名空间。
如果声明一个函数参数使用一个名字但是没有类型,它的缺省类型为item*。 如果一个函数声明中省略了结果类型,它的缺省结果类型为item*。
一个函数声明的参数被认为是其作用域为函数体的变量。一个函数声明如果有一个以上的同名参数,将引发一个静态错误(static error)[err:XQ0039]。函数参数的类型可以是任何用一个序列类型(SequenceType)(参见
2.4 Types)表示的类型。
下面的例子说明一个本地函数的声明和使用,它接收一个employee元素的序列,按部门(department)汇总之,返回一个dept元素序列。
- 利用一个函数,准备位于丹佛(Denver)的雇员的总计。
· declare function local:summary($emps as element(employee)*)
· as element(dept)*
· {
· for $d in fn:distinct-values($emps/deptno)
· let $e := $emps[deptno = $d]
· return
· <dept>
· <deptno>{$d}</deptno>
· <headcount> {fn:count($e)} </headcount>
· <payroll> {fn:sum($e/salary)} </payroll>
· </dept>
· };
·
· local:summary(fn:doc("acme_corp.xml")//employee[location = "Denver"])
将函数参数转换为它们声明时的参数类型的规则,和将函数结果转换成它们声明的结果类型的规则,在
3.1.5 Function Calls中说明。
函数声明可以递归——就是说,它可以引用它自己。其函数体相互引用的相互递归函数也是允许的。下面的例子声明了一个递归函数,计算一个节点层次的最大深度,并调用此函数来查找一个特定文档的最大深度。在其声明中,用户声明的函数local:depth调用缺省函数命名空间的内置函数empty和max。
- 查找名为partlist.xml的文档的最大深度。
· declare function local:depth($e as node()) as xs:integer
· {
· (: A node with no children has depth 1 :)
· (: Otherwise, add 1 to max depth of children :)
· if (fn:empty($e/*)) then 1
· else fn:max(for $c in $e/* return local:depth($c)) + 1
· };
·
· local:depth(fn:doc("partlist.xml"))
因为在类型定义作用域(
constructor function)中,
构造函数(in-scope type definitions)已经为每一个用户定义的原子类型被有效地声明了,如果序言试图声明一个与这些类型中任一个有相同扩展QName(expanded QName)的函数,将引发一个静态错误(static error)[err:XQ0034]
注意:如果 XQuery 的一个未来版本支持用户声明的函数的重载,将会在以一个节点作为参数的函数和同名的以一个原子值为参数的函数之间产生歧义(因为在必要时,一个函数调用自动抽取一个节点的原子值)。一个这样的 XQuery 未来版本的设计者能通过编写适当的规则来控制函数重载,从而避免这样的歧义。尽管如此,涉及到这个可能性的用户,可以在调用需要原子值的函数时,选择从节点中显式地抽取原子值。