How do i read json from an post input in Xquery code?

Viewed 205

I am sending the below POST data to an XQuery module. When I try to read it, I have tried everything, fn:doc, from-json, etc...., I cannot find a solution. Depending of what I try to do, I either get coercion error or data is not a string.

Can anyone help me put the Artist value to an $artist variable, etc...?

Here is the post request:

curl --anyauth --user admin:admin -H "Content-Type: application/json; charset=UTF-8" -H "Accept: application/json" -X POST -g "http://localhost:8030/LATEST/resources/jsontest/" -d "{"Artist" :"bowie","Weeks" : {"gte" :"1960-01-01","lte" :"2020-12-31"},"Genres":"","Released":"" }"*

and here is my code reading the POST request:

declare function test:post(
    $context as map:map,
    $params  as map:map,
    $input   as document-node()*
) as document-node()*
{
  xdmp:log($input)
};

and the result is this:

{"Artist":"bowie", "Weeks":{"gte":"1960-01-01", "lte":"2020-12-31"}, "Genres":"", "Released":""}

which looks like a json document (to my untrained eye), but i can't figure out how to "read/assign" the value for Artist (in this case "bowie") and put it in a variable.

  • I tried fn:doc, because I thought it should be a document-node
  • I tried let $artist := $input/Artist/data(), but get a coercion error
  • I tried many other option (from-json, etc..)

but I always wind up with some sort of error

how can I get access to the values in the JSON? I've been running around in circles through the MarkLogic documentation and different searches and nothing seems to work.

1 Answers

The subtle differences between a document-node(), a JSON object, a JSON document stored in the database as an object-node(), and a string of JSON can be confusing. Especially when if you log it and see the stringified representation, you just see the JSON and it is difficult to tell what it really was.

When in doubt, xdmp:describe() and xdmp:type() can be helpful for that. They can help tell you what sort of "thing" you really have.

When the method interface says you will get a document-node(), that is a generic container for stuff. It will have a child node(), but that node could be lots of things. It could be an XML document and the children could be comments, processing instructions, element, or it could be a binary(), text(), or a json:object. In this case, you know that you are going to have a JSON object.

You can use XPath to select that child node:

$json := $input/node()

With a JSON Object, you can access the Artist property by using map:get()

let $artist := map:get($json, "Artist")

The difference between a JSON object and an object-node() (JSON document stored in the database within MarkLogic) is that a regular JSON Object is just a data structure, but the object-node() lives in the database and has been parsed and saved as database nodes tied to indexes, so there are extra features and functionality. After inserting a JSON object into the database, if you later retrieve it with fn:doc(), then you it will be a JSON object-node() in the database, and you can do some neat things such as use XPath against it.

xdmp:from-json-string() can be used to parse a JSON string. It will construct a JSON object (which is basically a specialized map).

You can convert that object-node() into a JSON object using xdmp:from-json().

It is also possible to serialize the json:object map as an XML structure using json:transform-from-json() and then transform that XML structure back into a json:object using json:transform-to-json().

Related