或者不用都是允许的。
也许现在的问题是,“用不用数据类型呢?”数据类型改变了编程的方式,也许应该说明我如何使用数据类型,我为何认为应有限度地使用数据类型。
我发现在函数的输入参数和返回值中使用数据类型就足够了,如 清单 1 所示。
清单 1. local:add 函数xquery version quot1.0quotdeclare function local:adda as xs:integer b as xs:integer as xs:integer xs:integerabdocument ltresultgtlocal:add12lt/resultgt如果运行 exampleSimple Ant 目标文件,结果就会输出到控制台,同时将文件保存到/result 目录下,如 清单 2 所示。
清单 2. 处理 example.xq 的结果Buildfile: src/build.xmlexample:echo Source document ignored - query does not
access the context itemecho ltxml versionquot1.0quot encodingquotUTF-8quotgtecho ltresultgt3lt/resultgtBUILD SUCCESSFULTotal time: 1 second除了看到 addition 在 XQuery 中能正常工作以外,我还将 local:add 函数的输入和返回值限定为 XML Schema 数据类型 xs:integer。
如果提供错误的输入 — 比如 local:add1quot2quot(2 被作为一个字符串提供),将会看到有用的类型错误信息。
不考虑数据类型,XQuery 仍然会生成错误,不过这是因为 XQuery 知道加法运算符()应该用于处理数字。
静态类型分析 意味着所有可能的类型错误(主要是指数据类型不匹配)发生在分析而不是执行代码的时候,就是说任何调用 local:add 函数的外部 XQuery 代码都需要在运行前通过静态分析。
通过这种保守的静态检查,数据类型可以改进应用程序的总体质量,因为在部署代码之前必须保证数据类型匹配。
简言之,即使 XML 没有定义的数据类型或者相关的模式,使用基本数据类型也能带来一些好处。
此外,还要考虑应用程序在将来利用 XML Schema 数据类型。
永恒的话题 4:没有更新机制XQuery 的最初设想没有考虑设置更新 XML 文档(在文件系统、数据库等中)的特性。
2008年 3 月,Candidate Recommendation of XQuery Update Facility(XQF — 见 参考资料)纠正了这个弱点。
W3C XQuery Working Group 可能没有时间考虑将这方面的特性加入到 XQuery 核心标准中。
当时没有涉及意味着通过反馈 XQuery 处理程序的实际实现可能会修改 XQueryUpdate Facility 规范。
这种经验在创建规范的时候是很有必要的,我确信 XQF 规范定义的比较好。
回页首XQuery 的局限与不足尽管大多数永恒的话题都消失了,对于当前的 XQuery 语言仍然有一些问题值得讨论。
缺少 system-property 函数XSLT 有一个非常有用的函数, 可以查询处理程序本身的信息,返回处理程序供应商或者当前 XSLT 版本之类的属性。
如果需要创建跨 XQuery 处理程序执行的 XQuery 应用程序,这种自省是很有用的。
我只能说 XQuery 没有,或者 — 可能更准确 — XPath 2.0 没有任何机制执行该函数或者可供 XQuery 使用的方法。
警告:使用扩展函数可能造成锁定多数 XQuery 实现都增加了自己的第三方函数,提供了各种各样的附加功能。
使用这些扩展函数最明显的问题是,如果依赖于特定实现提供的专用非标准功能,有可能造成 XQuery代码不兼容。
得到 EXSLT 的支持前我一直与这种供应商锁定问题作斗争。
XQuery 也出现这种情况我毫不奇怪。
要说明扩展函数对开发的副作用,最好的办法 是举一个简单的例子。
我调查了三种 XQuery实现(见 参考资料)中的 random 函数的实现,因为难以通过小的例子说明情况可能有多么复杂: eXist XML 数据库: o util:random xs:double o util:randoma as xs:integer xs:integer o math:random xs:double MarkLogic XML 数据库: o xdmp:randommax as xs:unsignedLong 作 为 xs:unsignedLong Saxon XQuery 和 XSLT 处理程序: o math:random: 返回 0 和 1 之间的随机数 o random:random-sequence1seed: 根据初始种子返回一组 随机数六种不同的 random 函数,如果扩展函数库中生成随机数都有这么多变化,可以想象编写兼容的 XQuery 代码有多么困难。
eXist XML 数据库的三种函数可能显示了最糟糕的情况,因为 util:random 和 math:random 之间的关系不明确。
我认为这是由于对不同作者编写的两个函数重构(常见于开放源代码)造成的。
最糟糕的是,这两个函数可能代表新旧不同的版本。
此外,eXist 的 util:random 函数增加了更多的变化,它接受 xs:integer 种子参数并返回一个 xs:integer(而不是其他两个函数返回的 xs:double)。
MarkLogic 定义了一个 randommax 函数返回一个随机的、 介于零和最长 64 位数之间的无符号整数。
返回类型 xs:unsignedLong 代表 0 和 709551615(含)之间的无符号整数。
该函数允许提供同类型的 max 参数来定义最大值。
Saxon 选择支持 EXSLT,应该是一件好事(有关 EXSLT 请参见 参考资料)。
但是由于目前 EXSLT 和 XQuery 没有联系,使用 Saxon random 函数有点混乱。
对于 random 函数的 XQuery 处理程序实现的混乱情况,Saxon random 函数可能是最好的一个例子。
多种不同的名称空间再加上不同的函数签名,要想创建跨平台的运行时 XQuery 应用程序基本上是不可能的,因为多数 XQuery 处理程序在静态分析阶段就会被阻塞。
默认名称空间的麻烦XQuery 支持定义默认名称空间,所有不带前缀的输出元素都出现在默认名称空间中。
利用这一特性,可以定义 XQuery XML 输出中所有无前缀元素的默认名称空间,如 清单 3 所示。
清单 3. 声明默认元素名称空间xquery version quot1.0quotdeclare default element namespace quothttp://www.w3.org/1999/xhtmlquotlthtmlgt ltbodygt test lt/bodygtlt/htmlgt运行这段代码将得到结构良好的输出结果(如 清单 4 所示),所有元素都存在于http://www.w3.org/1999/xhtml 名称空间中。
当然也可选择将名称空间绑定到前缀,虽然这样可能会麻烦一些,因为使用文档类型定义(DTD)的时候要求元素没有前缀。
清单 4. no-namespace.xq 的输出ltxml versionquot1.0quot encodingquotUTF-8quotgtlthtml xmlnsquothttp://www.w3.org/1999/xhtmlquotgtltbodygttestlt/bodygtlt/htmlgt因此如果声明默认名称空间,就会带来几个问题。
首先,没有名称空间怎么能产生不带前缀的结果元素呢?奇怪的是,XQuery 允许把前缀绑定到一个空字符串,表示将元素放到默认名称空间中。
如 清单 5 所示。
清单 5. no 名称空间绑定declare namespace my-no-namespace quotquot这样,my-no-namespace:myelement 就有一个 no 名称空间。
但是如果在 no 名称空间中需要不带前缀但仍使用定义的默认名称空间的元素,麻烦就来了。
在 XQuery 中这样做是不可能的,就是说必须在 XQuery 处理之后再借助于文本操作来删除前缀和这些人为的名称空间声明。
所幸的是,这些古怪的概念在各种 XQuery 处理程序中都是一致的。
能否保留要看其用例是否足够强大到可以保证其应用。
没有 XQuery 求值或者动态 XPath在 XSLT 中不通过第三方函数就无法动态生成和计算 XPath。
这种局限同样适用于XQuery,就是不能对动态生成的 XPath 求值。
此外,也不能动态计算生成的 XQuery。
XQuery 没有 eval 类型的函数执行生成的 XQuery 代码,使得一些惯用法难以实现。
所幸的是,多数成熟的 XQuery 处理程序都增加了自己的 eval 函数。
在具有良好架构的代码中,不要使用该函数,尽管用起来通常很方便。
现在您可能有点糊涂了。
我要说的是,在任何计算环境中动态求值代码都需要知道什么时候使用它,什么时候不使用它。
异常处理机制XQuery 允许使用 fn:error 函数随机抛出错误,但是没有提供检测静态或动态错误以及处理错误的设施。
我想 fn:error 方法基本相当于 throw 。
一些 XQuery 处理程序提供了 try/catch 之类的扩展函数,但一般来说最好避免使用这些扩展函数。
太多的可选特性XQuery 实现要符合规范,必须提供一组核心特性。
除了核心特性集之外,实现者还可以决定是否提供某些可选特性,如下所列: Schema import:模式直接通过序言导入 Schema 验证:用模式技术验证 XML 静态类型分析 :在分析阶段检查各种静态类型错误 模块:支持库模块和模块导入 序列化:将查询结果序列化为 XML 文档 轴:支持 ancestor、ancestor-or-self、following、following-sibling、preceding 和 preceding-sibling 轴将模式导入和处理作为可选特性是明智的决策,避免很多潜在的冲突。
还有一个次要的好处是避免了 XQuery 核心出现依赖关系。
静态分析作为可选特性也是可取的。
XQuery 中的模块是创建可重用代码库的基础,很难让人理解为何是可选的。
另外一个同样困难的选择是为何开发人员不希望控制 XQuery 的 XML 输出,有一个先例,XSLT 将序列化定义为标准(参见 参考资料)。
序列化存在不一致性 — 比方说,查询结果通常是一系列的项,而不是一个 XML 文档。
但多数处理程序都默认输出 XML。
比如 清单 6,被称为 quine。
在编程中,quine 指的是执行时输出自身代码清单的一段代码。
Quine 对于说明任何编程语言的局限都是一个有用的测试,XQuery 的测试如清单 6 所示。
清单 6. XQuery 的 quine 测试xquery version quot1.0quotdeclare variable s:xquery version quot1.0quotdeclare variable s:quotquotfn:substrings144sfn:substrings45fn:substrings 144sfn:substrings45执行 exampleQuine Ant 目标程序将得到 清单 7 所示的结果。
清单 7. 用 XQuery 处理 quine 的结果ltxml versionquot1.0quot encodingquotUTF-8quotgtxquery version quot1.0quotdeclare variable s:quot xquery version quot1.0quotdeclare variable s:quotquotfn:substrings144sfn:substrings45quotfn:substrings144sfn:substrings45由于空白的原因,这段代码惟一的问题是需要使用一个处理程序专有的选项来控制版本/编码的输出 — 不算太完美。
它说明了 XQuery 核心的序列化部分。
更重要的是多数 XQuery处理默认使用 XML 输出序列化,尽管上述查询的结果是一系列字符串!再看看上述最后一个可选特性,XQuery 可选的支持某些 XPath 轴差不多是令人反感的。
最初,人们认为这些轴实现起来很难,但后来证明这些可选的轴可以用其他支持的轴来表示。
多数 XQuery 处理程序都实现了这些可选的轴,因此不需要再讨论这个问题了。
将其交给实现者吧我刚刚讨论了您可能决定实现的很多特性。
此外,还有一些可选特性没有定义,因此必须根据需要进一步定义其功能。
允许实现者决定如何 实现某个特性会带来很多变化。
下面列出了一些这样的特性: 支持 XML 1.0 和 Namespaces 1.0 或者 XML 1.1 和 Namespaces 1.1 实现扩展函数 预声明名称空间,包括默认元素和函数名称空间 内置模式,可在查询中使用其类型名,在验证中使用元素和属性声明 内置全局变量以及和默认值有关的选项 指定支持的排列法 静态文本 Base-URI 的默认值、边界空间策略、空序规定、名称空间复制方式、构 造方式、默认排列法和顺序方式 序列化选项的默认值 外部变量定义您可能知道列出的大多数可选特性。
但是,如果让实现者自由选择如何编写软件以保证兼容性是很难的。
我认为对于 XQuery,我们可能确定的可选特性太多,最终只会带来不兼容性。
对 XQuery 的优劣评价就到此为止。
现在您已经了解 XQuery 开发中的不足,我们来介绍一些编程惯用法和例子。
使用扩展函数在您自己的代码寻找一种使用扩展函数的方法。
如果只有 system-property 函数如果有 system-property 函数,实现组成 XQuery 函数库就相对容易些,后者包括 XQuery 处理程序专用的函数。
清单 8 中的代码说明了如何包装不同的实现,如何在各种供应商 random 函数实现中切换(参见 上一节)。
清单 8. util:random 伪代码declare function util:ra.