在 Java 环境中使用 XQuery.docx
- 文档编号:18604867
- 上传时间:2023-08-20
- 格式:DOCX
- 页数:30
- 大小:36.71KB
在 Java 环境中使用 XQuery.docx
《在 Java 环境中使用 XQuery.docx》由会员分享,可在线阅读,更多相关《在 Java 环境中使用 XQuery.docx(30页珍藏版)》请在冰点文库上搜索。
在Java环境中使用XQuery
在Java环境中使用XQuery
在Java应用程序中使用XQuery搜索文档
BrettMcLaughlin (brett@newI),作家,编辑,O'ReillyMedia,Inc.
简介:
XML数据格式很难搜索,但是最近随着XQueryAPI的出现,XML搜索变得非常灵活和简单。
对于使用SAX、DOM、JDOM、JAXP等处理XML文档的Java™程序员来说,工具箱中增加XQueryAPIforJava是一件值得高兴的事。
现在Java程序员不用再求助于系统调用或者笨拙的API就能利用XQuery的强大功能了,Sun提供了一套完整的、标准化的包。
本文的标签:
introduction, java, xquery之
标记本文!
发布日期:
2008年5月29日
级别:
中级
其他语言版本:
英文
访问情况 4307次浏览
建议:
0 (添加评论)
平均分(共3个评分)
SQL数据库、XML数据和查询
虽然编程领域—特别是Java编程—不断发展,可供选择的标准的数量也在增长。
换句话说,越来越多的API得到Sun的认可或者批准。
标准化的结果是越来越多的开发者背弃了自己最具竞争力的技术,而去学习新技术。
要掌握的最有吸引力和价值的是那些和数据处理有关的工具和API。
无论应用程序多么酷或者智能,说到底只有能够处理数据才有用。
同时,虽然API数量的不断增长,但流行和通用的数据格式数量却不断减少。
虽然有些数据管理员仍然使用面向对象的数据库管理系统或者XML驱动的数据库,但关系数据库(RDBMS)已成为主流,而且仍然是大部分数据管理员的选择。
因此Java开发人员必须通过JDBC(数据库连接)或者JDO(JavaDataObjects)与SQL数据库交互。
SQL数据库与其他数据库
虽然本文提到了查询和数据库,但所指的是SQL数据库—也称为关系数据库。
不过XML数据库甚至对象数据库都有一些很好的应用程序。
如果对XML数据库感兴趣,可以查看DB2®Express-C,可免费下载(链接参见 参考资料)。
最明显的一点是,XML数据库在XML文档和关系数据之间进行不必要的转换。
本文还认为,XQuery实际上已变为数据库查询语言,因为XML数据库以XML格式存储数据。
数据库之外的数据基本上也都以XML作为标准数据格式。
XML虽然冗长但是健壮,Java语言中处理XML的API可能比其他语言都多。
无论是解析、数据绑定还是转换,如果应用程序不能处理XML,就会被认为有局限性甚至有点落后。
两者看似无关,—数据往往保存在SQL数据库中,数据库之外的数据越来越多地采用XML格式—,但是却造成了一些独特的问题。
SQL数据库容易查询,而XML文档则不是这样。
消费者希望能够方便地搜索数据,数据库中的数据查询方便,但是XML文档中的数据就不那么容易了。
显然,将XML格式的数据塞到数据库中以方便搜索的做法是行不通的。
于是就出现了XQuery—相应的也就有了XQueryAPIforJava(XQJ)。
回页首
XQuery:
三种技术
经常用到的缩写词
∙API:
应用程序编程接口
∙DOM:
文档对象模型
∙GUI:
图形用户接口
∙IDE:
集成开发环境
∙JAXP:
JavaAPIforXMLProcessing
∙SAX:
SimpleAPIforXML
∙W3C:
万维网联盟
∙XML:
可扩展标记语言
简言之,XQuery就是用于定义XML文档搜索的一种语言。
就像SQL赋予了SELECT和FROM特定的含义一样—在一定的上下文中—XQuery定义了正斜杠(/)和地址符号(@)以及其他一些关键字和关键字符的意义。
XQuery的核心包括三部分:
1.XPath规范:
在XML文档中选择零个、一个或多个节点的方法。
2.选择特定XML文档、为XPath返回的节点增加选择条件的附加语法
3.API—比如XQJ,XQueryforJavaAPI—用具体的编程语言对XQuery表达式求值
要真正精通XQuery,必须切实掌握好这三个方面。
对于Java程序员来说,显然就意味着要学习XPath、学习新增的XPath语法结构,然后将其与基于Java的API结合起来对XML文档使用XQuery表达式。
好消息是XPath和XQuery语法都非常简单明了。
如果曾经使用UNIX®shell、MacOSX终端或者DOS窗口研究过目录结构,就具备了必要的基础。
掌握了小于(<)、大于(>)和等于(=)这些运算符的基本用法外,您称得上是大半个XPath专家了。
回页首
XPath基础
事实上,XQuery差不多完全依赖于另一个XML规范,即XPath规范。
XPath的作用基本上就是定义创建指向XML文档某一部分的路径 的方法。
比如,XPath /play/act/scene 就是指 play 根元素下的 act 元素下的所有 scene 元素。
XPath是相对路径
最基本的XPath使用元素名和正斜杠。
默认情况下,XPath以XML文档中的当前位置开始。
因此如果使用DOM,比如导航到 speech元素,然后指定路径 speaker,则指向当前位置的 speech 元素中的所有 speaker 元素。
因此XPath的求值是相对于文档中的位置而言的。
从当前节点移动
要移动到文档的根元素,可在路径前加上正斜杠。
无论在文档的什么位置,/play 可以查找名为 play 的根元素。
用 ../ 可以选择当前元素的父元素。
应该能够看出这实际上非常类似与目录结构。
路径 ../../personae/title 将从当前元素上溯两层,然后依次寻找personae 和嵌套在其中的 title 元素。
选择属性
除了元素外还有很多可供选择的其他内容。
比如这个XPath:
/cds/cd@title。
它返回根元素cds下 cd 元素上所有的“title”属性。
要记住,@ 返回的不是属性的值而是属性本身。
因此,@isbn 将选择所有名为isbn属性而不是这些属性的值。
此外,XPath中的属性指的是属性名和属性值(请参阅后面的 关于节点 一节)。
选择文本
文本嵌套在元素中
对于元素和元素中的文本,通常的想法是认为元素“具有文本”。
经常看到这样的说法,“title 元素的值是‘YouCan'tCountOnMe.’”。
这是不正确的,实际上文本嵌套在元素中。
可以认为文本属于一个元素,但是和属性具有文本值完全不同。
最好的办法是认为文本确实嵌套在元素中。
元素是文本的双亲,文本不是它所嵌套的元素的值。
就像选择元素和属性一样,也可选择元素中的文本。
如果XPath以元素名结束,比如 /cds/cd/title,则选择的是元素—而且不 包括这些元素中的文本。
如果需要元素中的文本,可使用 text() 语法。
因此要取得所有CD的文字标题,可以使用 /cds/cd/title/text() 这样的路径。
该路径不提供任何元素,而是指定元素中的文本。
XPath选择一组节点
有效使用XPath的一个关键是要认识到XPath始终计算的是节点集。
这个集合可能包含零个、一个或多个节点,但XPath的结果必定 是集合。
多数人在编写XPath的时候认为:
该路径返回一个元素、一个属性或者文本,但事实并非如此。
不过这也不是绝对的。
如果使用DOM,应该已经对节点有所了解了。
对于DOM来说,XML文档中的一切—元素、属性和文本—都是节点。
元素有元素节点,属性(包括属性值)有属性节点,元素中的文本则是文本节点。
因此路径 ../../personae/title 最终将选择 title 元素,实际上返回一个节点集。
这个集合可能包含零个(没有匹配的元素)、一个或者多个节点。
集合中的所有节点都是名为“title”的元素。
随着路径变得更加复杂,有可能选择一个更大的集合—也许同时包括属性和元素,或者同时包括文本和元素—无论如何这些路径最终都是选择一个节点集。
牢记这一点是正确使用XQuery的关键。
通过XPath选择一个节点集,而使用XQuery则通常是按照一定条件选择这些节点的一个子集,也有可能连接多个节点集然后应用搜索条件。
只要记住集合中的元素可能有多种类型(元素、文本或者属性),就能更好地编写路径并保证得到预期的结果。
回页首
增加XPath的选择性
前面我们看到了如何根据节点名(元素和属性)以及父节点(文本或者选择给定节点的所有子节点)来选择节点集。
这本身已经非常强大了,不过XPath还提供了更多的选择性,即使用所谓的谓词。
谓词语法
MicrosoftInternetExplorer(及其他一些浏览器)的错误
XPath规范要求,谓词 [1] 指向集合的第一个节点,换句话说,XPath节点集的索引是从1开始的。
但是,InternetExplorer多数版本的XPath实现都错误地采用零基数索引,[1] 指向数组中的第二 项,[0] 表示第一项。
您需要在浏览器中测试,但集合中第一项的索引为 [1] 而不是 [0],这才是正确的。
谓词是用于已有节点集的部分表达式。
谓词放在方括号 [ 和 ] 中。
作用于谓词左侧的路径所定义的节点集。
比如路径 /cds/cd 选择了根元素“cds”中的所有 cd 元素。
假设需要第一张唱片,可以使用谓词来实现:
/cds/cd[1]。
它返回路径 /cds/cd 选择的第一个节点。
谓词可用于任何节点集
要记住,谓词作用于谓词本身左侧的节点集。
但是这并不意味着谓词只能出现在XPath的最后面。
可以将XPath本身看作是路径的集合,每个路径都返回一个节点集,路径后面的部分作用于该集合并进一步细化。
因此 /cds/cd/title 实际上是三个路径:
1./cds 返回根元素“cds”(只含一个元素节点的集合)
2.cd(相对于上一个节点集)返回上一节点集中嵌套的所有 cd 元素
3.title(同样相对于上一节点集)返回上一节点集中嵌套的所有 title 元素
谓词必须作用于节点集,但是可作用于任何 节点集。
/cds[1]/cd[2]/title[1] 这样的路径是完全合法的。
它选择了 /cds 所选节点集中的第一项,/cds[1]/cd 所选节点的第二项,/cds[1]/cd[2]/title 所选节点的第一项。
注意:
该路径中有些部分毫无意义,比如使用 / 选择根元素然后再使用 [1] 谓词总是返回集合中的第一个(惟一的一个)元素。
只有当节点集本身为空,即给出的根元素名称和文档实际的根元素不同,这种情况下才不会返回任何元素。
但是作为一个例子—包括从技术的角度看—XPath本身以及使用的谓词都没有问题。
超越谓词中的数值索引
当然,只能用数值引用位置的API作用是很有限的。
这样的模型中,您必须知道需要的项到底在什么位置。
不过XPath提供了更多的选择。
首先,在谓词中可以使用 last() 函数选择集合中的最后一项,不论集合中包含多少项。
/cds/cd[last] 选择文档中最后一个cd。
使用 position() 函数还可以选择在特定位置之前或者之后的所有项。
position() 函数返回给定节点在集合中的位置。
比如,假设需要前5张唱片,可以使用路径 /cds/cd[position()<6]。
这样就能选择 position() 结果小于6的所有节点。
根据数据选择节点
最后—对于这里关于XPath的简要介绍而不是详细讨论来说—还可以根据节点的子元素或者节点的属性来选择节点。
就像XPath后面的部分依赖于前面路径所决定的节点集一样,集合的谓词也依赖于所应用的集合。
谓词除了能够使用小于(<)和大于(>)这样的运算符外,还可根据选中节点的数据而不仅仅是这些节点在整个集合中的位置进行选择。
比方说要选取属性“style”为“folk”的所有CD。
表达式应该首先选择全部CD,然后把这些CD的 style 属性和“folk”进行比较。
其XPath形式为 /cds/cd[@style='folk']。
按照前面的说明,这个表达式的意思应该很清楚了。
首先,通过 /cds/cd 选择了一个节点集。
然后使用谓词 @style 取出每个节点的“style”属性。
前面已经提到,@ 表示属性。
并且该属性是关于已经选择的节点集的(即所有 cd 元素)。
接下来把这些属性的值和字符串“folk”比较。
属性匹配的返回,其他的则在结果集中排除掉。
该方法也可用于所选集合的嵌套元素。
假设文档结构如清单1所示。
清单1.CD清单文档的结构
--Moretrackelements...-->
--MoreCDs...-->
比方说如果希望取得包含10条或更多音轨的CD。
首先要选择全部CD元素,即前面多次用到的路径:
/cds/cd。
然后使用谓词得到关于所选集合的特定节点集的项数,即嵌套在需要返回的节点集之中的 track-listing 元素下所包含的 track 元素节点的个数。
最后还需要对这些节点计数,XPath提供了 count() 函数。
此外还需要把这个数字与10比较。
于是得到了路径:
/cds/cd[count(track-listing/track)>=10]。
关于XPath谓词中的矛盾
如果阅读得足够仔细,可能会注意到XPath对元素文本和属性的处理是不一致的。
前面,我提到属性节点包括属性及其值作为一个信息单位来处理。
但是在谓词中,@type 这样的表达式引用的不是整个 type 属性节点而仅仅是属性值。
从而能够与其他值进行比较(如@type='reggae')。
同样,也可在谓词中引用元素文本,如 /cds/cd[title='Revolver']。
这里用嵌套在 cd 中的 type 元素的值和“Revolver”比较。
而且和属性节点一样,违背了看待元素的几条标准规则。
一般来说,元素节点是文本节点的父节点,但这里谓词实际上引用了元素中的文本。
这种轻微的规则违背不是大问题,只要您知道有这种情况,而且能够转换对元素和属性的两种不同思考方式即可。
只需要明确什么时候将属性及其值看作一个节点,什么时候引用属性值;类似的,也知道什么时候元素包含其他文本节点,什么时候文本值能够和其他值比较。
回页首
看看XQuery
XPath无疑非常强大,但也有其局限性。
最突出的是,它很大程度上只适合静态数据。
换句话说,需要针对特定文档编写XPath查询,提供和元素、属性、文本比较的具体数据来使用谓词和XPath。
此外,XPath也没有任何控制结构(如if/else语句),除了简单的比较外也不能执行任何处理。
坦白地说,这些限制对多数非程序员来说算不上大问题。
但是对于Java(或者C#、Python)程序员,习惯了完整的编程语言的强大功能,很快就想到需要XPath本身功能之外的方法搜索XML文档。
于是XQuery理所当然地登场了。
选择文档
XQuery中很少使用但是非常重要的一个特性是能够指定应用XPath的文档。
前面我们已经将路径 /cds/cd[title='Revolver'] 应用到了一个特定的文档,但在XQuery中可使用 doc() 函数指定文档。
因此如果搜索 catalog.xml,可使用XQuery表达式doc("catalog.xml")/cds/cd[title='Revolver']。
这个小函数的好处在于可以编写代码来以编程的方式选择文档(比如根据用户的输入),或者遍历一组文档(比如网络中所有的iTunes目录)并分别应用该语句。
回页首
XQuery和FLWOR
当然除了简单地文档选择外,XQuery还提供了更多的功能。
它的FLWOR功能尤为强大。
FLWOR是“for、let、where、orderby、return”的缩写。
这都是可用于XQuery表达式以便得到更精确结果的子句。
不是flower
不清楚创造这个缩写词的人为何选择FLWOR而不是FLOWR,第一个没法拼读,第二个看起来像“flower”。
原因很明显,多数表达式中子句的顺序是for、where、orderby 和 return。
但还剩下 let,它可以出现在XQuery之前或之中。
缩写为FLWOR是因为标准化XML规范的小组(W3C)选择了它,不过最好不要使用FLOWR以免在其他熟悉XML的朋友面前丢脸。
对于SQL老手来说,应该感到有些熟悉了。
WHERE和ORDERBY都是SQL查询中常见的部分。
对于程序员来说, for 应该比较眼熟。
下面是关于FLWOR子句的简要说明:
∙for:
使用 for 遍历节点集。
在很多方面,for 就将节点集的当前值赋给变量从而操作该变量。
∙let:
使用 let 可以为变量赋值,但是(很快将看到)和其他FLWOR子句相比,let 用的比较少。
∙where:
where 允许向节点集应用选择条件,除了XPath原有的机制意外。
当然,您将看到在很多查询中 where 并不比XPath强,只不过把XPath的谓词转移了一个地方。
∙orderby:
orderby 子句不改变或者筛选数据,仅用于排序结果集,XPath只能按位置排序,该子句允许按照其他数据排序。
∙return:
使用 return 子句允许您操作操作节点集,随后返回除该节点集以外的结果。
有可能在选择节点集、排序并筛选之后,只返回结果的子元素,return 是实现这种功能的关键。
我们再稍微深入地看看这些子句。
使用for子句
for 子句的用法和Java和C#中的用法基本相同。
其格式如下:
for$variable-nameinXPath
...
其中的变量名可以是任何一般的标识符,如 x。
变量一般最好根据用途命名(如 firstName 或r title),不过由于这个变量基本上是一个循环计数器,也可使用单个字母。
XPath没有限制。
/cds/cd 是一个很好的例子。
再比如:
for$cdindoc("catalog.xml")/cds/cd
...
如此而已。
因此变量 $cd 将取得XPath /cds/cd 返回的每个节点的值。
其中的 ... 代表XQuery表达式的其他部分,后面将讲到。
对于程序员来说,这个语句实际上和下面的语句没有区别:
for(inti=0;i CDcd=cdArray[i]; //ProcessCD } 或者像列表那样: for(Iteratori=cdList.iterator();i.hasNext();){ CDcd=(CD)i.next(); //ProcesseachCD } 使用let为变量赋值 先暂缓上面对XQuery的讨论,let 子句用于为变量赋值。 您可能已经看到,XQuery中通过在标识符前加上美元符号($)来定义变量。 多数情况下按照上述方法使用XQuery中的变量,即通过 for 子句隐式建立变量,而不是使用 let 子句显式地定义变量。 不过也有可能需要使用显式的变量。 应该这样做: let$docName: ='catalog.xml' for$cdindoc($docName)/cds/cd ... 这里将搜索的文档赋给一个变量。 XQuery中的赋值使用 : = —除非曾经用过Pascal—可能有点奇特。 如果在更真实的环境中,可能用一个函数迭代遍历一组XML文档,依次将这些文档名赋给 $docName。 这样就能选择每个 文档中的每个 cd 元素,按照同样的方式分别处理。 用return子句完成查询 为了完成查询,我们先跳过FLWOR中的排序子句。 现在我们已经得到了: let$docName: ='catalog.xml' for$cdindoc($docName)/cds/cd ... 接下来就要返回一些东西了。 查询选择了所有 cd 元素,但是返回这些元素没有多少用处—虽然这就是需要的节点集。 这里不返回这些元素,我们假设需要某种更容易识别的内容,比如存储在 title 元素中的每张CD标题。 这就用到 return 了。 let$docName: ='catalog.xml' for$cdindoc($docName)/cds/cd return$cd/title/text() 首先选中了所有的 cd 元素。 然后依次将得到的节点赋给 $cd。 最后, return 子句返回的不是元素本身,而是包含目标数据的子元素“title”。 一定不要 犯下面的错误: let$docName: ='catalog.xml' for$cdindoc($docName)/cds/cd return/cds/cd/title/text() 这里有三个明显的问题: ∙首先它忘记了XQuery的目的,返回了一个XPath路径而没有执行任何查询。 ∙其次,没有使用 doc($docName) 返回数据,该变量指定了要从中选择CD的文档。 ∙最后,也是最重要的,该表达式将忽略对 for 子句返回的节点集所执行的筛选或排序操作。 后面还要用到这样的查询,其重要性将更加明显。 目前,先要记住必须保证 for 子句定义的变量同时出现在 return 子句中。 这一简单的法则可以保证查询得到预期的结果。 用where选择 where 增强了XQuery的选择能力。 XQuery中的 where 子句和SQL中一样,在选择中增加 where 子句是为了进一步细化结果集。 这是一个非常简单的例子: let$docName: ='catalog.xml' for$cdindoc($docName)/cds/cd where$cd@type='reggae' return$cd/title/text() 该查询返回所有瑞格舞曲唱片的标题。 不需要进一步解释,where 子句非常简单。 通过 and 还可建立更加复杂的条件: let$docName: ='catalog.xml' for$cdindoc($docName)/cds/cd where$cd@type='reggae' andcount($cd/
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 环境中使用 XQuery 环境 使用