跳转至内容

XQuery/时间比较与 XQuery

来自维基教科书,开放书籍,开放世界

你有两个包含时间戳的相同项目列表。你想比较这些项目以查看哪些项目更新。

我们将编写一个函数来比较两个列表中项目的 时间戳。

样本数据集

[编辑 | 编辑源代码]
let $list1 :=
<list>
   <item dateTime="2009-06-01T11:59:00.000-05:00">apples</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">bananas</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">carrots</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">eggplant</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">grapes</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">oranges</item>
</list>

let $list2 :=
<list>
   <item dateTime="2009-01-01T11:59:00.000-05:00">apples</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">bananas</item>
   <item dateTime="2009-03-01T11:59:00.000-05:00">carrots</item>
   <item dateTime="2009-02-01T11:58:00.000-05:00">eggplant</item>
   <item dateTime="2009-02-01T12:00:00.000-05:00">grapes</item>
   <item dateTime="2009-04-01T11:59:00.000-05:00">oranges</item>
</list>

样本 XQuery 函数

[编辑 | 编辑源代码]
declare function local:older($list1 as node()*, $list2 as node()*) as node()* {
for $item1 in $list1/item
   let $item2 := $list2/item[./text() = $item1/text()]
   return
      <div>
       {attribute {'class'} 
           {if ( xs:dateTime($item1/@dateTime) lt xs:dateTime(fn:current-dateTime) )
            then 'older'
            else 'newer'
            }
       }
       {$item1/text()}
      </div>
};

比较屏幕截图

[编辑 | 编辑源代码]

样本测试驱动程序

[编辑 | 编辑源代码]
<html>
   <head>
   <style language="text/css">
  <![CDATA[
    body {font-family: Ariel,Helvetica,sans-serif; font-size: medium;}
    h2 {padding: 3px; margin: 0px; text-align: center; font-size: large; background-color: silver;}
    .left, .right {border: solid black 1px; padding: 5px;}
    .older {background-color: pink;}
    .left {float: left; width: 390px}
    .right {margin-left: 410px; width: 390px}

  ]]>
  </style>

   </head>
   <body>
      <h1>Older Items on Second List Report</h1>
      <div class="left">
         <h2>List 1</h2>
         {for $item in $list1/item return <div>{$item/@dateTime} dateTime={string(fn:current-dateTime)}</div>}
      </div>
      <div class="right">
         <h2>List 2</h2>
         {for $item in $list2/item return <div>{$item/text()} dateTime={string($item/@dateTime)}</div>}
      </div>
      <br/>
      <p>The pink items are older items.</p>
      <div class="left">
         <h2>Items on 2 Older Then 1</h2>
         {local:older($list1, $list2)}
      </div>
      <div class="right">
         <h2>Items on 1 Older Then 2</h2>
         {local:older($list2, $list1)}
      </div>
   </body>
</html>

执行

或者,两个排序列表可以整理起来以推导出更新集。这里将项目包装在 div 中以携带关于合并的附加信息。列表 1 中但不在列表 2 中的项目标记为新建,列表 2 中但不在列表 1 中的项目标记为要删除,列表 1 中比列表 2 更新的项目标记为更新。


declare function local:merge($a, $b  as node()*)  as node()* {
    if (empty($a) and empty($b))
    then ()
    else  if (empty ($b) or $a[1] lt $b[1])
    then  (<div class="add">{$a[1]}</div>, local:merge(subsequence($a, 2), $b))
    else  if (empty($a) or $a[1] gt $b[1])
    then  (<div class="delete">{$b[1]}</div>,local:merge($a, subsequence($b,2)))          
   else   (<div  class="{ if (xs:dateTime($a[1]/@dateTime) gt xs:dateTime($b[1]/@dateTime))
                          then "newer" 
                          else "older"}"> 
              {$a[1]}
           </div>,
            local:merge(subsequence($a,2), subsequence($b,2))
           )
   };

样本数据和主脚本稍作更改

declare option exist:serialize "method=xhtml media-type=text/html";

let $list1 :=
<list>
   <item dateTime="2009-06-01T11:59:00.000-05:00">apples</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">bananas</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">carrots</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">cabbage</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">eggplant</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">grapes</item>
 </list>
 
let $list2 :=
<list>
   <item dateTime="2009-01-01T11:59:00.000-05:00">apples</item>
   <item dateTime="2009-02-01T11:59:00.000-05:00">bananas</item>
   <item dateTime="2009-03-01T11:59:00.000-05:00">carrots</item>
   <item dateTime="2009-02-01T11:58:00.000-05:00">eggplant</item>
   <item dateTime="2009-02-01T12:00:00.000-05:00">grapes</item>
   <item dateTime="2009-04-01T11:59:00.000-05:00">oranges</item>
</list>

return

<html>
   <head>
   <style language="text/css">
  <![CDATA[
    body {font-family: Ariel,Helvetica,sans-serif; font-size: medium;}
    h2 {padding: 3px; margin: 0px; text-align: center; font-size: large; background-color: silver;}
    .left, .right {border: solid black 1px; padding: 5px;}
    .newer{background-color: lightgreen;}
    .older{background-color: lightred;}
     .delete{background-color: red;}
    .add{background-color: green;}
   .left {float: left; width: 390px}
    .right {margin-left: 410px; width: 390px}
 
  ]]>
  </style>
 
   </head>
   <body>
      <h1>Update Report</h1>
      <div class="left">
         <h2>List 1</h2>
         {for $item in $list1/item return <div>{$item/text()} dateTime={string($item/@dateTime)}</div>}
      </div>
      <div class="right">
         <h2>List 2</h2>
         {for $item in $list2/item return <div>{fn:current-dateTime} dateTime={string(dateTime(current-dateTime))}</div>}
      </div>
      <br/>
      <p>Green are new, light green are newer and red to be removed</p>
      <div class="left">
         <h2>Merged Lists</h2>
         {local:merge($list1/item, $list2/item)}
      </div>
    </body>
</html>

执行

华夏公益教科书