【问题标题】:In XQuery, how to evaluate xpath from a string?在 XQuery 中,如何从字符串评估 xpath?
【发布时间】:2014-08-22 20:34:35
【问题描述】:

我有一个XQuery 脚本,我想在将新文档导入数据库时​​对其进行评估。我想从一个字符串中评估一个带有谓词的Xpath 表达式,并使用结果来选择合适的集合。

如果所有代码都在XQuery 文件中,它会完美运行。我想让它比这更动态并阅读XPath 表达式 -> 动态集合映射。然后,在每个文档中,当XPath 表达式返回一个节点时,我就找到了正确的集合。

这可能吗? xdmp:unpath() 功能不够用。它不支持谓词。 xdmp:eval()xdmp:value() 似乎可以工作,但我不能让它们只针对单个文档工作。要么是这样,要么就是在 500 个左右的文档之后开始失败(对于任何 XPath 表达式返回 true)。

我希望能够做这样的事情:

(: Get XML from MarkLogic Record Loader. :)
let $doc := xdmp:unquote($XML-STRING, $UNQ-NAMESPACE, $UNQ-OPTIONS)

(: Get XPath expression from database. :)
let $xpath := doc("/mappings.xml")/mappings/rule/xpath

(: Evaluate. :)
let $result := some-function($doc, $xpath) 

(: Use the result.
return
    if(fn:count($result) > 0)
        ( $collection )
    else
        ()   

是否有一些构造可以使“some-function($doc, $xpath)”工作?

似乎XQueryXPath 表达式是语法的一部分,不能用字符串代替。我习惯了像 Perl 这样的其他语言,其中 XPath 始终是一个字符串,这样的事情是微不足道的。

谢谢。

【问题讨论】:

  • 详细说明您使用xdmp:eval()xdmp:value() 尝试的内容可能会对您有所帮助。我希望您可以简单地执行let $result := xdmp:value(concat($doc, $xpath)) 并且它会起作用。
  • 尝试像 Perl 中的正则表达式一样考虑 XQuery 中的 XPath。在 Perl 中使用正则表达式进行元编程是可能的,但这些技术可能并不明显。在 XQuery 中使用 XPath 进行元编程是类似的。
  • xdmp:value 是我尝试的首批解决方案之一。更多分析见下文。我在记录加载器中执行此操作,但事情并没有按应有的方式工作。
  • 我最后一次用那个特定的表达式“xdmp:value(concat($doc, $xpath))”试了一下,它确实工作正常。但由于下面详述的其他原因,我仍然坚持使用 XSL 解决方案。

标签: xquery marklogic


【解决方案1】:

正确的工具是xdmp:value。不过,您可能在语法上遇到了一些问题。我会用这个:

xdmp:value(concat('$doc', $xpath))

构造一个相对于 $doc 的表达式,类似于 $doc/a/b/c。然后我们可以在当前上下文中评估该表达式,其中 $doc 已经定义。

let $doc := xdmp:unquote('<x>some xml <i>from somewhere</i></x>')
let $xpath := '/x/i'
return xdmp:value(concat('$doc', $xpath))
=>

<i>from somewhere</i>

注意xdmp:unquote 产生一个文档节点,所以第一步是x 根元素。

你可以把它封装在你自己的函数中,然后你就可以让some-function($doc, $xpath) 工作了。

declare function local:my-unpath($doc as node(), $xpath as xs:string)
as item()*
{
  xdmp:value(concat('$doc', $xpath))
};

let $doc := xdmp:unquote('<x>some xml <i>from somewhere</i></x>')
let $xpath := '/x/i[starts-with(., "from")]'
return local:my-unpath($doc, $xpath)

【讨论】:

  • 我最后一次用这个特定的代码尝试了它,它成功了。但是,我将坚持使用 XSLT 解决方案。我尝试了与此非常相似的其他构造,但结果非常奇怪。如果删除单引号,则会失败。如果您尝试使用 $doc/$xpath,它似​​乎会匹配整个数据库而不是指定的文档。我更喜欢带有一个明显表达的优雅解决方案,而不是具有一个正确、非明显表达和其他类似表达返回不正确结果的解决方案。
  • 并且在调试过程中,XSLT方案的性能与xdmp:value()方案相当。
【解决方案2】:

您还可以将 XML 配置文件重写为 XSLT,然后使用 xdmp:xslt-invoke 对其进行评估。它仍然是 XML,只是格式略有不同。每个规则都是一个模板match,返回一个带有集合名称的xsl:text 结果。

【讨论】:

  • 这是迄今为止最好的解决方案。我一直是 XSLT 的粉丝,但还没有在 MarkLogic 中使用过它。请参阅下文,了解对奇怪地甚至不返回正确结果的替代方案的一些分析。
【解决方案3】:

听起来你在寻找xdmp:unpath()

【讨论】:

  • 听起来他有复杂的谓词。例如xdmp:unpath('$doc/x/i[starts-with(., "from")]') 会抛出XDMP-UNPATH,但可以与xdmp:value 一起使用。同时,我不会使用 xdmp:eval: 这个用例的矫枉过正。
猜你喜欢
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-03
  • 1970-01-01
相关资源
最近更新 更多