2017-04-17 100 views
1

我在XQuery中有一個練習題。邏輯:如何計算XQuery中的最長持續時間?

  • 獲得持續時間最長的課程。

這是XML文件的結構:

<training> 
    <course id="1"> 
     <start>20170101</start> 
     <end>20170401</end> 
    </course> 
</training> 

我已經做到了這一點:

for $x in doc("LMSGI06")//course 
let $max := max($x/end - $x/start) 
return 
    <duration>{$max}</duration> 

這是我查詢的結果:

<duration>300</duration> 
<duration>400</duration> 
<duration>400</duration> 
<duration>400</duration> 
<duration>10000</duration> 

我的查詢列出了所有課程的持續時間,但我只需要最長的課程持續時間。請注意,XML文件中的日期具有數字格式,而不是日期格式,因此,我正在嘗試減去日期,如十進制數字。

回答

2

您目前正在評估您的for循環中的max()。一個數字的max()就是這個數字。

你可以得到所有的持續時間的max(),然後選擇與時間過程:

let $doc := doc("LMSGI06") 
let $maxDuration := max(
        for $x in $doc//course 
        return $x/end - $x/start 
        ) 
return $doc//course[(end - start) eq $maxDuration] 

或者你可以命令通過其持續時間的課程,然後選擇第一個:

(
    for $course in doc("LMSGI06")//course 
    order by $course/end - $course/start descending 
    return $course 
)[1] 
3

如果你使用的撒克遜人,那麼另一個選擇是撒克遜:最高的功能:

saxon:highest(doc("LMSGI06")//course, 
       function($course) { $course/(end - start) } 
      ) 

但是,您使用十進制減法而不是日期/持續時間減法是不健全的。考慮2016031-20170101(一天:小數差= 8870)與20170201-20170205(四天:小數差= 4)的時間間隔。第二個持續時間較長,但有一個較小的小數差。所以你應該真正將值轉換爲xs:date,並將它們作爲xs:date值減去以獲得xs:duration值。

2

如果不使用撒克遜但仍然要處理每個course只有一次,你可以重新實現saxon:highest(...)功能純的XQuery 3.0

declare function local:highest($seq, $key-func) { 
    head(
    fold-left($seq,(), 
     function($max, $curr) { 
     let $key := $key-func($curr) 
     return if($max[2] >= $key) then $max else ($curr, $key) 
     } 
    ) 
) 
}; 

轉換日期字符串到xs:date數據類型可以按如下所示完成:

declare function local:to-date($str) { 
    xs:date(concat(substring($str, 1, 4), '-', 
    substring($str, 5, 2), '-', substring($str, 7))) 
}; 

使用這兩個函數,解決方案t o您的鍛鍊與正確的日期比較變得非常簡單:

local:highest(
    doc("LMSGI06")//course, 
    function($course) { 
    local:to-date($course/end) - local:to-date($course/start) 
    } 
)