4 模塊與序言Modules and Prologs
::= |
|||
::= |
|||
::= |
|||
::= |
(Setter Separator)* ((Import | NamespaceDecl | VarDecl | FunctionDecl) Separator)* | ||
::= |
XMLSpaceDecl | DefaultCollationDecl | BaseURIDecl | ConstructionDecl | DefaultNamespaceDecl | DefaultOrderingDecl | ||
::= |
|||
::= |
";" | ||
::= |
[定義:一個查詢可以由一個或多個稱爲模塊(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說明。一個模塊只有當它有查詢體時才被計算。
::= |
"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";
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
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
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
::= |
"declare" "base-uri" StringLiteral |
基URI聲明(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
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
DefaultNamespaceDecl |
::= |
(("declare" "default" "element") | ("declare" "default" "function")) "namespace" StringLiteral |
缺省命名空間聲明(Default namespace declarations)用在序言(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
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;
SchemaImport |
::= |
"import" "schema" SchemaPrefix? StringLiteral (("at" StringLiteral) ("," StringLiteral)*)? | |
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 "";
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
::= |
"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>
VarDecl |
::= |
"declare" "variable" "$" VarName TypeDeclaration? ((":=" ExprSingle) | "external") | |
VarName |
::= |
QName | |
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;
除了在[XQuery 1.0 and XPath 2.0 Functions and Operators]中說明的內置函數之外,XQuery允許用戶聲明他們自己的函數。函數聲明指定函數的名字、參數的名字和數據類型、以及結果的數據類型。所有的數據類型使用2.4 Types中描述的語法指定。函數聲明使被聲明的函數被添加到它出現的模塊資源(module resource)的函數簽名(function signatures)中。
FunctionDecl |
::= |
"declare" "function" QName "(" ParamList? (")" | (")" "as" SequenceType)) (EnclosedExpr | "external") | |
ParamList |
::= |
Param ("," Param)* | |
Param |
::= |
"$" VarName TypeDeclaration? | |
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未來版本的設計者能通過編寫適當的規則來控制函數重載,從而避免這樣的歧義。儘管如此,涉及到這個可能性的用戶,可以在調用需要原子值的函數時,選擇從節點中顯式地抽取原子值。