4

This is a trivial simplification of my attempt to develop a function in the MarkLogic XQuery manager. The function I am trying to write must be capable of receiving a null node as input. I've been trying to pass () to mean "empty node" and it seems to just crash without any sort of trace.

For example, the trivial example shown is expected to simply return the figure "1", but does not. If I instead pass a small non-empty XML document then the trivial example works.

What is wrong with my reasoning, please, on passing an empty node?

declare function local:x ($i as node()) as xs:string*

{  let  $x := "1"

   return $x
};

local:x ( () );
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
Latitude42
  • 43
  • 3

1 Answers1

5

Your problem is that your function expects exactly a single node() and not an empty-sequence()(which is what you're providing by calling your function like this: local:x( () ))

An empty sequence can't be cast to a node. If you want to provide a function that expects zero or one nodes you can do it like this:

declare function local:x($i as node()?) as xs:string* {
  let $x := "1"
  return $x
  (:
    Also instead of doing the above you could also simply return the string directly by simply typing it out:
    "1"
  :)
};

The question mark is the key here:

Some functions accept a single value or the empty sequence as an argument and some may return a single value or the empty sequence. This is indicated in the function signature by following the parameter or return type name with a question mark: "?", indicating that either a single value or the empty sequence must appear.

(Taken from W3C)

One thing you should be aware about is that an empty sequence is not the same as e.g. an empty text node!

let $emptySeq := () (:This actually has no value at all:)
let $emptyText := text {} (:This simply is an empty node, but it is still a node!:)
return (fn:empty($emptySeq), fn:empty($emptyText))

This will return (true, false)

Riiverside
  • 788
  • 7
  • 12
  • This is great information. You can probably give me exactly the hint I need if I give you a little more information. MarkLogic allows iterative calls to an XQuery function, and what I am attempting to do is provide a function argument that passes accumulated information to nested calls. So fop level call would be x (nothing, something) and nested calls would be x (something, something) – Latitude42 May 17 '17 at 20:22
  • 1
    Are you talking about function mapping? Anyway, if you think it fits in this question just edit your question and I'll try to adapt my answer. Otherwise just create a new question. – Riiverside May 17 '17 at 20:27
  • 2
    Thank you! You have led me right to my issue. I didn't know what function mapping meant but yes, that is the issue. When I learned how to turn it off, I did so and my silent failures changed to "invalid coercion" which is what you were describing to me in the first place. – Latitude42 May 17 '17 at 20:44
  • 3
    For posterity, one can disable function mapping with `declare option xdmp:mapping "false";`. I'd recommend using it in all your code. – grtjn May 18 '17 at 04:50
  • @Latitude42 Yeah I can relate to that. Forgot to disable it once and it took me extremely long to find out what was causing all the problems. I think that it can really be a nice feature and helpful sometimes, but has so many unpredictable side effects and makes it extremely hard to understand code, because there can be many places where function mapping kicks in which you often simply can't tell just by looking at the code(unless you really carefully examine the types of the parameters of a function call). I wonder why it is enabled by default, especially since it's non-standard. – Riiverside May 18 '17 at 18:02