2

MarkLogic 版本:8.0-3.2

看起来,如果在 search:search 选项节点(如 中)中有多个前缀不同但 URI 相同的命名空间声明,则<element xmlns:bar="myuri:baz" xmlns:foo="myuri:baz">除了第一个前缀之外的每个前缀都会在 search:search 调用中丢失。

这是预期的行为吗?它在 ML7.0-4.3 下不存在,并且我不知道在不同前缀下对同一命名空间 uri 的多个声明违反了 XML 命名空间或 xQuery 规范。

非常感谢任何见解。

测试设置脚本:

(:~
 : Two transactions:
 : (1) Create an element range index on element {myuri:baz}child in "Documents" database
 : (2) Insert a test document at /baz/test/test-baz.xml
 :
 : Expected output: empty sequence
 :)

(: Transaction (1): Set up index :)
xquery version "1.0-ml";

import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";

let $config := admin:get-configuration(),
    $dbid := xdmp:database("Documents"),
    $rangespec := admin:database-range-element-index("string", "myuri:baz", "child", "http://marklogic.com/collation/", fn:false(), "reject")
return
    try {
        admin:save-configuration-without-restart(
            admin:database-add-range-element-index($config, $dbid, $rangespec)
        )
    } catch($e) {
        "Index already exists? Check logs.",
        xdmp:log($e, "debug")
    }

;

(: Transaction (2): Insert test document :)
xquery version "1.0-ml";

declare namespace baz = "myuri:baz";

let $uri := "/baz/test/test-baz.xml",
    $document :=
        <baz:root>
            <baz:child>TEST</baz:child>
        </baz:root>
return
    xdmp:document-insert($uri, $document)

测试脚本(为了清晰/可读性而详细说明):

xquery version "1.0-ml";

import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";

(: additional-query: xmlns:foo first, xmlns:bar second; cts:element: foo:child. Succeeds. :)
declare variable $search-options-1 :=
  <options xmlns="http://marklogic.com/appservices/search">
    <additional-query xmlns:foo="myuri:baz" xmlns:bar="myuri:baz">
      <cts:element-range-query operator="=">
        <cts:element>foo:child</cts:element>
        <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TEST</cts:value>
      </cts:element-range-query>
    </additional-query>
  </options>;

(: additional-query: xmlns:foo first, xmlns:bar second; cts:element: bar:child. Fails. :)
declare variable $search-options-2 :=
  <options xmlns="http://marklogic.com/appservices/search">
    <additional-query xmlns:foo="myuri:baz" xmlns:bar="myuri:baz">
      <cts:element-range-query operator="=">
        <cts:element>bar:child</cts:element>
        <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TEST</cts:value>
      </cts:element-range-query>
    </additional-query>
  </options>;

(: additional-query: xmlns:bar first, xmlns:foo second; cts:element: bar:child. Succeeds. :)
declare variable $search-options-3 :=
  <options xmlns="http://marklogic.com/appservices/search">
    <additional-query xmlns:bar="myuri:baz" xmlns:foo="myuri:baz">
      <cts:element-range-query operator="=">
        <cts:element>bar:child</cts:element>
        <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TEST</cts:value>
      </cts:element-range-query>
    </additional-query>
  </options>;

(: additional-query: xmlns:bar first, xmlns:foo second; cts:element: foo:child. Fails. :)
declare variable $search-options-4 :=
  <options xmlns="http://marklogic.com/appservices/search">
    <additional-query xmlns:bar="myuri:baz" xmlns:foo="myuri:baz">
      <cts:element-range-query operator="=">
        <cts:element>foo:child</cts:element>
        <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TEST</cts:value>
      </cts:element-range-query>
    </additional-query>
  </options>;

for $search-options in ($search-options-1, $search-options-2, $search-options-3, $search-options-4)
return
    try {
        let $test := search:search("", $search-options, 1) instance of element(search:response)
        return
            if ($test) then "PASS"
            else "FAIL" (: won't reach :)
    } catch($e) {
        $e/error:format-string/fn:string(.)
    }

测试输出(注意错误子字符串“No string element range index for child ”---no namespace)

经过

XDMP-ELEMRIDXNOTFOUND: cts:search(fn:collection(), cts:and-query(cts:element-range-query(xs:QName("bar:child"), "=", "TEST", ("collat​​ion = http://marklogic.com/collat ​​ion/"), 1), ()), ("score-logtfidf", cts:score-order("descending")), xs:double("1"), ( )) -- 没有子元素的字符串元素范围索引http://marklogic.com/collat​​ion /

经过

XDMP-ELEMRIDXNOTFOUND: cts:search(fn:collection(), cts:and-query(cts:element-range-query(xs:QName("foo:child"), "=", "TEST", ("collat​​ion = http://marklogic.com/collat ​​ion/"), 1), ()), ("score-logtfidf", cts:score-order("descending")), xs:double("1"), ( )) -- 没有子元素的字符串元素范围索引http://marklogic.com/collat​​ion /

更新:当祖先在不同前缀下多次声明相同的命名空间 URI 时,元素级命名空间声明(使用直接构造函数或通过 fn:QName() 序列化)也会在 ML8(不是 ML7)下中断

当任何祖先在不同的前缀下多次声明相同的 URI 时,前缀在 self::* 处丢失:

xquery version "1.0-ml";

import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";

(: Serialize namespace w/ fn:QName(), no namespace inheritance: PASS :)
declare variable $search-options-1 :=
  <options xmlns="http://marklogic.com/appservices/search">
    <additional-query>
      <cts:element-range-query operator="=">
        <cts:element>{fn:QName("myuri:baz", "child")}</cts:element>
        <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TEST</cts:value>
      </cts:element-range-query>
    </additional-query>
  </options>;

(: Serialize namespace w/ fn:QName(), namespace inheritance, declared once: PASS :)
declare variable $search-options-2 :=
  <options xmlns="http://marklogic.com/appservices/search">
    <additional-query xmlns:foo="myuri:baz">
      <cts:element-range-query operator="=">
        <cts:element>{fn:QName("myuri:baz", "child")}</cts:element>
        <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TEST</cts:value>
      </cts:element-range-query>
    </additional-query>
  </options>;

(: Serialize namespace w/ fn:QName(), namespace inheritance, declared twice: FAIL :)
declare variable $search-options-3 :=
  <options xmlns="http://marklogic.com/appservices/search">
    <additional-query xmlns:foo="myuri:baz" xmlns:bar="myuri:baz">
      <cts:element-range-query operator="=">
        <cts:element>{fn:QName("myuri:baz", "child")}</cts:element>
        <cts:value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TEST</cts:value>
      </cts:element-range-query>
    </additional-query>
  </options>;

for $search-options in ($search-options-1, $search-options-2, $search-options-3)
return
    try {
        let $test := search:search("", $search-options, 1) instance of element(search:response)
        return
            if ($test) then "PASS"
            else "FAIL" (: won't reach :)
    } catch($e) {
        $e/error:format-string/fn:string(.)
    }

输出 ML7.0-4.3:

经过

经过

经过

输出 ML8.0-3.2:

经过

经过

XDMP-ELEMRIDXNOTFOUND: cts:search(fn:collection(), cts:and-query(cts:element-range-query(xs:QName("bar:child"), "=", "TEST", ("collat​​ion = http://marklogic.com/collat ​​ion/"), 1), ()), ("score-logtfidf", cts:score-order("descending")), xs:double("1"), ( )) -- 没有子元素的字符串元素范围索引http://marklogic.com/collat​​ion /

4

3 回答 3

3

如果您在 XQuery 上下文中直接使用 Search API,则可以使用fn:QName()来获得元素 QName 的一致序列化:

<cts:element>{ fn:QName("myuri:baz", "child") }</cts:element>

评估为:

<cts:element xmlns:_1="myuri:baz">_1:child</cts:element>

或者,xs:QName()将使用可用的范围内前缀:

declare namespace foo ="myuri:baz";
<cts:element>{ xs:QName("foo:child") }</cts:element>

评估为:

<cts:element xmlns:foo="myuri:baz">foo:child</cts:element>

当然,如果您将 REST API 与存储的搜索选项一起使用,这种方法将无济于事。

于 2015-11-06T01:37:55.077 回答
1

我可以确认它在 7.0-5.1 中运行,但不在 8.0-4 中。我已在内部将此报告为错误。

看起来附加查询的处理方式已经改变。但是,如果您将命名空间声明中的两个元素之一向下移动,则不会出现任何错误。也许这对您来说是一个有用的解决方法?

于 2015-12-21T09:06:24.623 回答
0

我相信 Search API 一直有这个限制。我同意这个意外是不幸的——标准不认可这个限制——但是你是否很难通过为每个命名空间 uri 使用一个且只有一个前缀来解决这个限制?如果不出意外,这会使声明更简单。

于 2015-11-06T00:24:38.410 回答