XQuery 基于 xml 结构创建 where 子句作为一种动态 where 子句

XQuery Create where clause based on xml structure as a kind of dynamic where clause

这是关于 XQuery - 我使用 MarkLogic 作为数据库。

我有如下示例中的数据:

<instrument name="myTest1" id="test1">
   <daten>
      <daily>
         <day date="2016-02-05">
            <screener>
               <column name="i1">
                  <value>1</value>
                  <bg>red</bg>
               </column>
               <column name="i2">
                  <value>1</value>
                  <fg>lime</bg>
               </column>
               <column name="i4">
                  <fg>black</bg>
               </column>
            </screener>
         </day>
      </daily>
   </daten>
</instrument>

我有很多 instruments,每个 instruments 在 daily element 和 screener 里面都有一个 manz columns,都有不同的名字。一些筛选器包含的列比其他筛选器多。每列可以包含一个值元素、一个 bg 元素和一个 fg 元素。

我想搜索满足特定条件的工具,即哪些列的子项具有特定值。示例:我想要一个所有工具的序列,在给定的一天,第 i1 列的值为 1,第 i2 列的 fg 为黑色

由于我有许多不同的条件,我不想在 XQuery where 子句中对它们进行硬编码。我这样做了几次并且它有效,但是代码有很多重复并且很难维护。

我的问题是,是否有可能以编程方式在 FLOWR 语句中构建 where 子句,也就是说,基于另一个 xml 结构,它可能如下所示:

<searchpatterns>
  <pattern name="test1">
     <c>
             <name>i1</name>
             <element>value</element>
             <value>1</value>
          </c>
          <c>
             <name>i2</name>
             <element>fg</element>
             <value>red</value>
             <modifier>not</modifier>
          </c>
  </pattern>
</searchpatterns>

这会找到那些仪器,其中筛选器有一个 i1 列,它本身的值为 1,而且它不能有带有红色 fg 的 i2 列。

当我以正常方式查询时,我会这样查询我的日期:

for $res in doc()/instrument
   where $res/daten/daily/day[@date="2016-02-05"]/screener/column[@name="i1"]/value/text()="1"
      and res/daten/daily/day[@date="2016-02-05"]/screener/column[@name="i2"]/fg/text()!="red"

我想根据 XML 结构生成这种 where 子句。

我对 MarkLogic 内置的 cts:search 函数和它周围的很多东西做了一些研究,但它似乎是为了别的东西(更多的用户交互搜索)

如果你能给我指明正确的方向,如果我想要的是可能的,我将不胜感激it.Thanks!

是的,这可以通过编程方式实现。如果你想检查一个元素是否满足序列中每个项目的测试,every ... satisfies 结构就会浮现在脑海中。所以在这种情况下它可能是:

for $res in doc()/instrument
where every $pattern in $searchpatterns/pattern/c satisfies (
  let $equal := $res/daten/daily/day[@date="2016-02-05"]/screener/column[@name = $pattern/name]/*[name() = $pattern/element] = $pattern/value
  return if ($pattern/modifier = "not") then not($equal) else $equal
)  
return $res

所以每个 $pattern 都会被检查。我假设 modifier 元素应该修改 equal 结构。所以我们首先检查元素是否满足相等条件,然后我们检查 modifier 元素是否等于 not。当然,应用同样的想法也可以用来实现其他修饰符。

doc()/instrument XPath 请求每个包含 instrument 元素的文档,然后过滤这些文档。

在可能的情况下,通常最好在 MarkLogic 中对文档建模,这样您就可以使用索引来检索尽可能少的文档。通常最好使用 cts:search() 而不是 XPath 来生成序列,这样您就可以直接使用索引。

在这种情况下,您可以考虑使用 name 属性的值作为元素而不是通用的 "column." 然后您可以生成一个 cts:element-query 匹配包含 cts:element-与名称中的值匹配的值查询。

希望对您有所帮助,