Reputation: 2192
In my application I am receiving a serialized structured query as a string. I need to convert this string into a query and execute the query.
I use cts:query
to construct the query:
declare namespace search = "http://marklogic.com/appservices/search";
(: External string variable received by the application. :)
let $query := "" ||
"<search:search xmlns:search='http://marklogic.com/appservices/search'>" ||
" <element-value-query xmlns='http://marklogic.com/cts'>" ||
" <element>element</element>" ||
" <text>value</text>" ||
" </element-value-query>" ||
"</search:search>"
(: extract cts query from search. :)
let $q := document {
xdmp:unquote($query)/search:search/*
}
(: construct cts query. :)
return cts:query($q/*)
This works fine if the cts query has a prefixed namespace like this:
<cts:element-value-query xmlns:cts="http://marklogic.com/cts">
<cts:element>element</cts:element>
<cts:text>value</cts:text>
</cts:element-value-query>
But not if a default namespace is used like in my first code example.
To make things clearer see this example:
xquery version "1.0-ml";
cts:query(
<element-value-query xmlns="http://marklogic.com/cts">
<element>element</element>
<text>value</text>
</element-value-query>
),
cts:query(
<cts:element-value-query xmlns:cts="http://marklogic.com/cts">
<cts:element>element</cts:element>
<cts:text>value</cts:text>
</cts:element-value-query>
)
The result of this xquery is:
cts:element-value-query(fn:QName("http://marklogic.com/cts","element"), "value", ("lang=en"), 1)
cts:element-value-query(fn:QName("","element"), "value", ("lang=en"), 1)
The default namespace is also used as the namespace for the "element". I guess this is the intended behavior.
Upvotes: 1
Views: 99
Reputation: 20414
You really need a prefix in this case to distinguish the cts:query elements themselves versus the index element you are addressing. Nothing stops you from changing the prefix yourself though. You could do that as follows:
xquery version "1.0-ml";
declare function local:qname($node, $ns, $prefix) {
if (fn:namespace-uri($node) eq $ns) then
if ($prefix eq '') then
QName($ns, local-name($node))
else
QName($ns, $prefix || ":" || local-name($node))
else
node-name($node)
};
declare function local:change-prefix(
$nodes as node()*,
$ns as xs:string,
$prefix as xs:string
)
as node()*
{
for $node in $nodes
return
typeswitch ($node)
case element() return
element { local:qname($node, $ns, $prefix) } {
$node/@*,
local:change-prefix($node/node(), $ns, $prefix)
}
case document-node() return
document {
local:change-prefix($node/node(), $ns, $prefix)
}
default return $node
};
cts:query(
local:change-prefix(
<element-value-query xmlns="http://marklogic.com/cts">
<element>myelement</element>
<text xml:lang="en">some text</text>
</element-value-query>,
"http://marklogic.com/cts",
"cts"
)
)
HTH!
Upvotes: 1
Reputation: 7335
The xdmp:with-namespaces() function supports the default namespace, so wrapping a call to xdmp:with-namespaces() around the call to the cts:query() deserializer might work:
http://docs.marklogic.com/xdmp:with-namespaces
That said, solving the problem by changing what produces the default namespace might be a better solution -- some folk regard the default namespace as an anti-practice because of the potential for confusion.
Hoping that's useful,
Upvotes: 1