Wagner Michael
Wagner Michael

Reputation: 2192

serialized structured query with default namespace

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

Answers (2)

grtjn
grtjn

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

ehennum
ehennum

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

Related Questions