我遇到了这个问题:我从各种网页上获取RSS订阅源,然后我需要按日期订购它们。我正在使用xquery进行xml操作,使用eXist数据库来存储rss / xml。 这是我的代码:
for $item in subsequence(collection('/db/bla/user/feed')//item[contains(title, $search)], $start, $num)
let $title:= $item/title/text()
let $desc:= $item/description/text()
let $link := $item/link/text()
let $date:= $item/pubDate/text()
order by $date
这不起作用。而且我认为问题出现在GMT和EST的不同时间,因此$ date的顺序不能正常工作。 请帮忙,我被困在这里。
提前致谢!
修改
以下是我从pubDate标记中获取的日期和时间格式:
Mon, 10 Dec 2012 13:32:24 EST
或
Mon, 10 Dec 2012 13:32:24 GMT
答案 0 :(得分:2)
尝试将$date
视为实际日期/时间:
let $date:= xs:dateTime($item/pubDate/text())
如果日期/时间的格式一致,您可以实现自己的转换器。在您的评论示例中,将为您提供最多问题的两个部分是月份和时区。月份需要是数字,您需要将时区转换为等效的UTC偏移量。
以下是一个例子:
declare variable $months := ('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec');
declare variable $timezoneMap :=
<map>
<tz>
<numeric>-05:00</numeric>
<alpha>est</alpha>
</tz>
</map>;
declare function local:formatDate($origdate as xs:string) as xs:dateTime {
let $dateTokens := tokenize($origdate,' ')
let $timezone := $timezoneMap/tz[lower-case($dateTokens[6])=alpha]/numeric/text()
let $month := string(index-of($months,lower-case($dateTokens[3])))
let $newDate := concat($dateTokens[4],'-',if (string-length($month)=1) then concat('0',$month) else $month,'-',$dateTokens[2],
'T',$dateTokens[5],$timezone)
return
xs:dateTime($newDate)
};
然后你可以使用这样的函数:
let $date:= local:formatDate($item/pubDate)
此外,如果您使用的是XQuery 3.0,则可以使用maps作为时区和月份:
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare variable $months := map{"jan":="01","feb":="02","mar":="03","apr":="04","may":="05","jun":="06",
"jul":="07","aug":="08","sep":="09","oct":="10","nov":="11","dec":="12"};
declare variable $timezoneMap := map{"est":="-05:00"};
declare function local:formatDate($origdate as xs:string) as xs:dateTime {
let $dateTokens := tokenize($origdate,' ')
let $newDate := concat($dateTokens[4],'-',$months(lower-case($dateTokens[3])),'-',$dateTokens[2],
'T',$dateTokens[5],$timezoneMap(lower-case($dateTokens[6])))
return
xs:dateTime($newDate)
};
答案 1 :(得分:1)
在XQuery中构建一些日期格式解析器可能不是最好的主意;你必须自己处理所有时区转换(更糟糕的是:夏令时...)。
eXist DB有自己的DateTime-Module基于java.text.SimpleDateFormat
。在使用之前必须编译和激活该模块,并且该模块不包含在eXists当前稳定版本中(但在1.4.3开发人员版本和版本2预发行版中)。
警告,它使用你系统的默认语言环境,在我的情况下不是英语(所以认识到日期失败了)。
如果您设法启用它(如果您没有,这可能是Database Administrator上的另一个问题,一个SO姐妹网站),您应该能够运行此代码来解析给定格式的日期:< / p>
import module namespace datetime = "http://exist-db.org/xquery/datetime";
datetime:parse-dateTime('Mon, 10 Dec 2012 13:32:24 GMT', 'EEE, d MMM yyyy HH:mm:ss Z')
如果您正在运行某些旧版本的eXist或因其他原因无法使用该模块,您可以在conf.xml
中激活Java绑定并直接调用此函数:
declare namespace sdtf="java:java.text.SimpleDateFormat";
declare namespace date="java:java.util.Date";
(: Parse given date format to java date :)
let $parse := sdtf:new('EEE, d MMM yyyy HH:mm:ss Z')
(: Output as close to XQuery's xs:dateTime as possible :)
let $format := sdtf:new("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
let $javadate := sdtf:parse($parse, 'Mon, 10 Dec 2012 13:32:24 GMT')
(: Use regex to insert missing ':' and finally cast to xs:dateTime :)
return xs:dateTime(fn:replace(sdtf:format($format, $javadate), '(.*)(\d{2})', '$1:$2'))
同样,如果不是默认情况,请记住将java语言环境设置为英语。
我想这至少应该在Saxon(定义了这个java绑定)和BaseX(我实际上在这里测试过)中运行良好。
答案 2 :(得分:1)
您可以使用Ryan Grimm的基于XQuery的Date Parser模块。它是为MarkLogic构建的,但是对其他系统也可以进行少量修改。请参阅https://github.com/marklogic/commons/blob/master/dates/date-parser.xqy。
正如模块中的注释所述,其支持的日期格式为: