Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing an array of dates in XQuery (MarkLogic v8 flavour)

My question seems trivial but could not figure out how to parse a string that contains a list of dates separated by commas. The parsing part of individual dates is not an issue but the empty values are. The trouble is the order of the dates are significant and some dates can be omitted. The dates are expected to be formatted in YYYY-mm-dd

So, the following are valid inputs and expected return values:

   ,2000-12-12,2012-05-03, ➔ ( NULL, 2000-12-12, 2012-05-03, NULL )
   2000-12-12,,2012-05-03  ➔ ( 2000-12-12, NULL, 2012-05-03 )

And here is my function signature

declare function local:assert-date-array-param( 
          $input as xs:string
        , $accept-nulls as xs:boolean?
) as xs:date*

I recognised the problem after realizing that there seems to be no equivalent of of NULL in XQuery for the returned values as placeholders for omitted dates, if you want to return a sequence, that is. Because empty sequences wrapped inside sequences are flattened to nothing.

I suppose, my fallback would be to use date like 1900-01-01 as the placeholder or return a map instead of a sequence, but I sure hope to find a more elegant way

Thank you,
K.

PS. I am working with MarkLogic v8 (and v9 soon) and any solution should execute with their XQuery processor.

UPDATE: thanks for both answers, in the end I chose to go with a placeholder date as XQuery works so nicely with sequences and anything else would have required some changes in other places. But the problem remains for the cases where the required return values are numerics. In this case, use of placeholder values would probably be not feasible. A null literal for xs:anyAtomicType would have solved the problem nicely, but alas.

like image 618
Kemal Erdogan Avatar asked Nov 27 '25 22:11

Kemal Erdogan


1 Answers

You could consider returning a json:array(), or an array-node{} with null-node{}'s inside. But perhaps a null-date placeholder is not as bad as it sounds:

declare variable $null-date := xs:date("0001-01-01");

declare function local:assert-date-array-param( 
  $input as xs:string,
  $accept-nulls as xs:boolean?
) as xs:date*
{
  for $d in fn:tokenize($input, "\s*,\s*")
  return
    if ($d eq "") then
      if ($accept-nulls) then
        $null-date
      else
        fn:error(xs:QName("NULL-NOT-ALLOWED"), "Date is required")
    else
      if ($d castable as xs:date) then
        xs:date($d)
      else if ($d castable as xs:dateTime) then
        xs:date(xs:dateTime($d))
      else
        fn:error(xs:QName("INVALID-DATE"), "Invalid date format: " || $d)
};

declare function local:print-date-array($dates) {
  string-join(for $d in $dates return if ($d eq $null-date) then "NULL" else fn:string($d), ", ")
};

local:print-date-array(
  local:assert-date-array-param(",2000-12-12,2012-05-03,", fn:true())
),
local:print-date-array(
  local:assert-date-array-param("2000-12-12,,2012-05-03", fn:true())
)

HTH!

like image 179
grtjn Avatar answered Dec 02 '25 04:12

grtjn



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!