How to use dynamic namespace with type switch?

Viewed 108
declare function local:change($node) 
{ 
  typeswitch($node) 
    case element(add) return 
      local:do-something()

    default return $node 
};
let $test1 := <test xmlns="http:example.com/A">
                <add>x1</add>
                <b>x</b>
             </test>

let $test2 := <test xmlns="http:example.com/B">
                <add>x1</add>
                <b>x</b>
             </test>

In the typeswitch when element add, doing some further processing. Code is generic. The documents that will be sent for processing will have the same elements but namespace can be different like one in the example.

How to provide the namespace dynamically in case element.

2 Answers

If you declare

declare namespace A = "http:example.com/A";
declare namespace B= "http:example.com/B";

you should be able to use

case element(A:add) | element(B:add)

at least in standard XQuery (https://www.w3.org/TR/xquery-31/#prod-xquery31-SequenceTypeUnion), I don't know whether Marklogic supports it.

I don't think sequence types allow a namespace wild card in the form of e.g. element(*:add) so I am not sure what to suggest for your high number of namespaces, check whether you need typeswitch and sequence type matching or whether you can't simply select *:add in a step of a path expression or a predicate e.g. if ($node[self::*:add]) e.g. instead of

typeswitch($node) 
    case element(add) return 
      local:do-something()
    ...

you can use

if ($node[self::*:add])
then local:do-something()
else $node 

One way to treat elements from different namespaces in the same way (as the same 'kind' of element), is put them into the same namespace, or into no namespace. Depending on what local:do-something() does, the typechecked copy might want to be empty, or to contain the original contents (as shown), or contain similarly namespace-stripped children.

declare function local:normalize-namespace($element){
    element { local-name($element) }  { $element/@*, $element/node() }
};

declare function local:change($node) 
{
  typeswitch(local:normalize-namespace($node)) 
    case element(add) return 
      local:do-something()

    default return $node 
};
Related