Chinaunix首页 | 论坛 | 博客
  • 博客访问: 762580
  • 博文数量: 803
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 5015
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-28 10:29
文章分类

全部博文(803)

文章存档

2011年(1)

2008年(802)

我的朋友

分类:

2008-10-29 11:42:45


  更新XQuery
  XQuery有了一些新特性,内容包括从原子化到跟踪文件结构。
  
  在"你所不了解的XQuery"(杂志,2003年5/6月刊)一文中,我介绍了XQuery,它是一项由万维网联盟(W3C)开发的技术,设计用来查询和操纵XML数据或任何能以XML形式出现的数据,如关系型数据库。那篇引文讨论了2002年11月发布的XQuery草案规范。2003年5月,W3C发布了新的XQuery草案规范,本文追踪报道了5月份发布的草案规范中最令人感兴趣的变化和新增加的特性,其中包括库模块、序(prolog)变量、外部函数以及用于调试、错误处理和格式化的新函数。
  
  变化
  5月草案增加了大量新特性,但是我首先讨论对现有特性所做的更改。有些更改是表面上的。 例如,document()输入函数(该函数使用给定的统一资源标识符[URI]返回一个文档)被改为一个新的更短的名字doc()。另外,曾经被写成{- comment -}的注释现在改用新的笑脸符号(: comment :)。是的,现在每个注释都成了一个笑话。
  
  有些更改则是更根本的。也许最重大的改动就是distinct-values()函数不再返回节点(节点是XML结构,如元素、文档、注释以及文本节点),它只返回原子值(如整数或字符串)。尽管该函数仍然接受节点和原子值,但只返回原子值。任何进入该函数的节点都会被"原子化"并被当作原子值,然后以原子形式返回。
  
  原子化的规则很复杂,这里给出一些基本的:由模式定义为布尔型的元素将被原子化为true/false布尔值。定义为整型的元素将被原子化为一个整数。没有被模式定义的元素将被原子化为节点的XPath字符串值(文本节点递归地连接在一起)。
  
  为了说明:
  distinct-values(apple,
  banana, "grape")
  
  返回值("apple","banana","grape"),假设在模式中没有声明 。在下面的例子中,如果我们假设 被模式定义为布尔型,那么下面的语句:
  
  distinct-values(0,
  false)
  
  返回false(),因为它是两个元素的原子值。记住false()是XQuery常量,表示"假"。
  
  现在你也许会想,"当我想返回节点时,可以使用distinct-nodes()函数。" 是的,但该函数只能根据节点标识删除重复节点(那些完全相同的节点,类似于中引用的等效节点)。没有能删除等效节点的函数。这会使查询变得复杂,因为没有办法能轻松地删除等效节点。
  
  回过头来看我以前的那篇文章"你所不了解的XQuery",你将发现有些示例会受到这一改动的影响。在那篇文章中,下面的查询返回了艺术家名字的惟一列表,其中每一个名字前后都带有 标记:
  
  distinct-values(document("itunes.xml")
  /itunes/Tracks/Track/Artist)
  
  示例输出类似于:
  
  Marc Cohn
  Pink Floyd
  
  现在,执行同样的查询则返回原子值:
  
  Marc Cohn
  Pink Floyd
  
  由于distinct-values()去掉了 标记(这是原子化过程的一部分),所以你必须在完成distinct-values()调用后添加标记,如下所示:
  
  let $artists :=
  distinct-values(doc("itunes.xml")
  /itunes/Tracks/Track/Artist)
  for $a in $artists
  return { $a }
  
  不是每种情况都是这么轻松地得到处理。看一下W3C 使用案例文档中的示例1.1.9.4在2002年11月版与2003年5月版中是如何变化的。该示例返回每位作者的著作列表。它使用了distinct-values(),根据2002年11月的规范,它的代码如下:
  
  
  {
  for $a in distinct-values(
  document("")
  //author)
  return
  
  { $a }
  {
  for $b in document(
  "")
  /bib/book
  where some $ba in $b/author
  satisfies deep-equal($ba,$a)
  
  ; return $b/title
  }
  

  }
  

  
  根据查询结果你不能直接分辨出姓和名,但每个 元素都由一个 和 名组成。distinct-values()调用返回具有惟一名字的 元素列表。对于2003年5月的规范,现在查询必须在姓和名上单独运行distinct-values(),而且在嵌套的FLWOR表达式中也没有将$a指定为惟一的作者:
  
  
  {
  let $a :=
  doc("")
  //author
  for $last in distinct-values($a/last),
  $first in distinct-values(
  $a[last=$last]/first)
  return
  
  { $last, $first }
  {
  for $b in
  doc("")
  /bib/book
  where some $ba in $b/author
  satisfies ($ba/last = $last and
  $ba/first=$first)
  return $b/title
  }
  

  }
  

  
  除了编写用户定义的distinct-deep-equal()外,没有更好的方法来完成这件事了,而该方法在纯XQuery中不能执行。(注:FLWOR(发音为"flower")表达式是XQuery的构建模块。这个名字来源于组成表达式的关键词For、Let、Where、Order by和Return}。
  
  新函数
  2003年5月的XQuery规范草案增加了三个新函数,它们肯定会非常有用。第一个是:
  
  trace($value as item()*,
  $label as xs:string) as item()*
  
  trace()函数允许在查询的中间进行printf风格的调试。该函数有两个参数:要显示的值(可以是任意多个项的序列)以及要显示的这个值的字符串标签。为方便起见,函数返回$value传递的值。trace()输出的位置由你的引擎来决定。
  
  该函数使你能够详细查看查询的内部过程。例如,下面的查询根据文档名返回在XQuery引擎中的所有文档的URI。通过增加一个trace()调用,我能够在排序前查看返回的每个URI:
  
  define function uris() as xs:string* {
  for $n in input()
  return trace(
  xs:string(document-uri($n)), "base:")
  }
  for $u in uris() order by $u return $u
  
  输出结果可能如下:
  
  2003-08-01 14:40:46 base: census.xml
  2003-08-01 14:40:46 base: ipo.xml
  
  当使用trace()和其他类似的函数时,记住在XQuery中每项内容都是一个表达式。没有语句!为了能够完成类似语句的操作,你可以采用在表达式之间加逗号的方法来创建一个序列。然后,单独计算每个表达式的值。在最终的结果序列中忽略所有返回空值的表达式。例如,下面是两个不影响结果的trace()调用:
  
  trace((), "starting query"),
  
  let $time := current-dateTime()
  let $ignored := trace($time, "Got time")
  return
  
  
  Current time is { $time }
  
  
  请注意第一个trace()调用后面的逗号。它使查询返回一个具有两个项的序列,第一个trace()调用的结果为空,因而被忽略。一般人不了解这一情况,但高级查询实际上就是返回一个序列,因此在这种特殊情况下两端的括号不是必需的。查询"5, "是完全正确的。此外,在这个示例中你会看到,当编写一个FLWOR表达式时,你可以执行let子句右侧的任意代码,并且忽略该值。
  
  5月份的草案还增加了error()函数:
  
  error($srcval as item()?)
  
  这个函数使用户能够报告一个错误,类似于抛出一个异常。$srcval被定义为item()?,意味着它可以是一个XML结构或原子,并且加上问号标记表示这是可选的。下面是一些示例应用:
  
  error()
  error("Missing source document")
  error(A beautifully
  formatted error
)
  
  error()调用就像发生异常时那样展开堆栈。遗憾的是,XQuery仍没有try/catch功能。因此,尽管你能抛出错误,但却不能从中恢复。
  
  在5月份的草案中最后一个引人注目的新增函数有一个奇怪的名字:round-half-to-even()。它有两种形式:
  
  round-half-to-even($srcval as numeric?)
  as numeric?
  round-half-to-even($srcval as numeric?,
  $precision as xs:integer) as numeric?
  
  在有一个参数的情况下,它的行为类似于round()函数,只是当一个数恰好落在其他两个数的中间时,它将参数取整为最接近的偶数值。数字理论家们会告诉你从统计学上讲这是一个更精确的取整算法。举例说明:
  
  round-half-to-even(1.5) = 2.0
  round-half-to-even(2.5) = 2.0
  round-half-to-even(2.51) = 3.0
  
  有第二个参数的情况使函数变得很有趣。第二个参数表示精确级,并允许将函数用于格式化小数值。例如:
  
  round-half-to-even(3.567, 2) = 3.57
  round-half-to-even(1113.567, -2) = 1100.0
  round-half-to-even(1 div 9, 3) = 0.111
  
  在声明中使用的数字数据类型是xs:decimal、xs:integer、xs:float、xs:double以及任何根据限制由它们导出的类型的一种简单表示。它用于XQuery规范中,但你不能在自己的查询中使用它。
  <
【责编:admin】
--------------------next---------------------

阅读(370) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~