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

My question seems trivial, but couldn't figure out how to parse a string containing a comma-separated list of dates. Parsing part of individual dates is not a problem, but empty values. The problem is that the order of the dates is significant and some dates can be omitted. Dates are expected to be formatted in YYYY-mm-dd format

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 figured out the problem by realizing that there seems to be no NULL equivalent in XQuery for return values ​​as placeholders for dropped dates if you want to return a sequence, that is. Because empty sequences wrapped inside sequences are flattened to zero.

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

Thank you
K.

PS. I'm working with MarkLogic v8 (and soon v9) and any solution needs to be done with their XQuery processor.

UPDATE: Thanks for both answers, in the end I decided to go with a placeholder date since XQuery works so well with sequences and something else would require some changes elsewhere. But the problem remains in cases where the required return values ​​are numbers. In this case, using placeholder values ​​would probably not be possible. A null literal for xs: anyAtomicType could solve the problem nicely, but alas.

+3


source to share


2 answers


You may consider going back json:array()

or array-node{}

from null-node{}

inside. But perhaps the null placeholder isn't 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())
)

      



NTN!

+2


source


Several options .. in addition to the above.



  • returns a sequence of functions that, when called, returns dates

    for $i in string-tokenize-to-sequence-of-strings()
    let $dt := my-parse-date($i)
    return function() { $dt ;}
    
          

    or

    return function() { return my-parse-date($i)  ; 
    
          

  • returns tokenized and verified, but unprocessed strings. Use "for" invalid, for example:

    ( "2014-01-22","","2017-03-30","" )
    
          

  • then there are arrays, maps, maps arrays and ... XML parseFunction () as xs: element () *:

    for ... return <date>{ parse-and-validate($value) } </date>
    
          

+1


source







All Articles