如何编写可以测试正在使用的 XQuery 版本的 XQuery?

Posted

技术标签:

【中文标题】如何编写可以测试正在使用的 XQuery 版本的 XQuery?【英文标题】:How can I write an XQuery that can test what version of XQuery is being used? 【发布时间】:2014-01-17 21:56:52 【问题描述】:

我正在编写一个 XQuery,它需要检查正在运行的 XQuery 版本(eXist、Saxon 等)。是否有标准函数可以返回 XQuery 的系统属性,例如版本、供应商等?

我知道有一些特定于系统的调用,例如 eXist 的

system:get-version()

但我正在尝试找到一个可以在所有平台上运行的标准函数。

例如在 XSLT 中我们有:

Version:
<xsl:value-of select="system-property('xsl:version')" />
<br />
Vendor:
<xsl:value-of select="system-property('xsl:vendor')" />
<br />
Vendor URL:
<xsl:value-of select="system-property('xsl:vendor-url')" />

它们对于 XQuery 的功能是否相似?

【问题讨论】:

XQuery 规范中没有任何内容支持这一点,但可能存在特定于实现的函数。您使用的是什么 XQuery 处理器? 我同时使用 eXist 和一些 Saxon HE。 xquery 版本“3.0”; let $properties := ('vendor', 'vendor-url', 'product-name', 'product-version', 'product-build') return for $property in $properties return 返回 exist-db.org"> 【参考方案1】:

Saxon 中似乎没有函数,但 eXist 有 system:get-version()

http://exist-db.org/exist/apps/fundocs/view.html?uri=http://exist-db.org/xquery/system&location=java:org.exist.xquery.functions.system.SystemModule

另外,虽然您没有使用它,但其他 SO 读者可能有兴趣知道 MarkLogic 有 xdmp:xquery-version()

http://docs.marklogic.com/7.0/xdmp:xquery-version

【讨论】:

我在 Saxon HE 中找不到任何可以指示正在运行的版本的函数。我确实发现您可以像这样查找特定于撒克逊的函数: declare function local:saxon() as xs:boolean try if (not(empty(function-lookup(xs:QName('saxon:parse') , 1)))) 然后 true() else false() catch * false() ;【参考方案2】:

您可以使用 XQuery 3.0 函数 function-lookup 检查是否存在特定于实现的函数来检查处理器。所有支持 XQuery 3.0 的处理器都应该能够处理这个。

declare function local:exist() as xs:boolean 
  try 
    if (not(empty(function-lookup(xs:QName('system:get-version'), 0))))
    then true()
    else false()
   catch * 
    false()
  
;

(: works only on Saxon PE and EE, fails in HE since HE does not support XQuery 3.0. It would be nice if saxon had a version function. :)
declare function local:saxon() as xs:boolean 
  try 
    if (not(empty(function-lookup(xs:QName('saxon:parse'), 1))))
    then true()
    else false()
   catch * 
    false()
  
;

declare function local:marklogic() as xs:boolean 
  try 
    if (not(empty(function-lookup(xs:QName('xdmp:xquery-version'), 0))))
    then true()
    else false()
   catch * 
    false()
  
;

declare function local:basex() as xs:boolean 
  try 
    if (not(empty(function-lookup(xs:QName('prof:time'), 1))))
    then true()
    else false()
   catch * 
    false()
  
;

declare function local:get-processor() as xs:string 
  if (local:exist()) then "eXist"
  else if (local:saxon()) then "Saxon"
  else if (local:marklogic()) then "MarkLogic"
  else if (local:basex()) then "BaseX"
  else "Unknown"
;

local:get-processor()

不幸的是,我无法使用高阶函数使其更优雅,因为特定于实现的函数是在实际调用函数之前执行的。但我相信这也可以写得更优雅。

【讨论】:

感谢示例代码!这在我们拥有 XQuery 3.0 的任何地方都能完美运行。不幸的是,我的一些项目仍在 XQuery 1.0 上。 Saxon HE 不支持 XQuery 3.0。 :-( 我认为这是迁移到 XQuery 3.0 的一个很好的理由! 我为 Saxon 添加了测试并将其放入 GIST:gist.github.com/dmccreary/8201987 @DanMcCreary 我编辑了我的答案,所以它也可以从 SO 中保存和访问。【参考方案3】:

这里有一个固有的问题,如果不同版本的 xquery 由不兼容的版本运行,则根本无法编译。你一般不能做一个 #if 版本 > 1 新的东西 #别的 老东西 #endif

一些供应商扩展提供版本信息,您可以使用“eval()”类型的 epression 来解决这个问题,但在纯 XQuery 中,我没有想到可以用来执行编译时有效的条件逻辑在当前版本上使用其他版本的某些功能。

【讨论】:

【参考方案4】:

在 Saxon-HE 的情况下很棘手,因为 Saxon-HE 仅支持 XQuery 1.0 并且不提供供应商扩展。然而,它确实提供了一种用于创建用户定义的扩展函数的机制,您可以使用它来实现您自己设计的询问函数。

或者您可以定义一个外部全局变量并从运行查询的应用程序中初始化它,假设应用程序在您的控制之下。

【讨论】:

以上是关于如何编写可以测试正在使用的 XQuery 版本的 XQuery?的主要内容,如果未能解决你的问题,请参考以下文章

xquery 转换在元素中创建空命名空间

如何使用 XQuery 检索父节点?

如何在 xquery 中格式化小数?

如何在 xquery 赋值中使用 if else

如何在 Saxon 的 XQuery 中动态引用 XML 文件

XQuery 更新:插入或替换取决于节点是不是存在不可能?