Jon
Jon

Reputation: 453

How do I put commas in the right places generating JSON in MarkLogic?

I'm trying to not have a comma after a curly brace if it was the last item.

  for $row in /md:row
  let $test := $row/md:test/text()
  let $last := $row/*[fn:position() = fn:last()]

  return (
   '{
    "test": {
    "type": "test",
    "test": [',$testa,',',$testb,']
    }      
   }',
   if($last)
   then ''
   else (',')
  )

Upvotes: 1

Views: 122

Answers (3)

grtjn
grtjn

Reputation: 20414

I fully agree with Charles's comments, and I like wst's string-join better than this, but for the sake of completeness, there is also the at statement that is part of FLWOR expressions. You could use it something like this:

  let $rows := (1 to 10)
  let $last := fn:count($rows)
  for $row at $index in $rows
  let $test := string($row)

  return (
   '{
    "test": {
    "type": "test",
    "test": [',$test,']
    }      
   }',
   if($index eq $last)
   then ''
   else (',')
  )

HTH!

Upvotes: 0

Charles Duffy
Charles Duffy

Reputation: 295639

In the given situation, where your output is JSON, use the json:transform-to-json call provided by MarkLogic for the purpose.

import module namespace json = "http://marklogic.com/xdmp/json"
  at "/MarkLogic/json/json.xqy";

json:transform-to-json(
  <json type="array" xmlns="http://marklogic.com/xdmp/json/basic">{
    for $row in /md:row
    let $test := $row/md:test/text()
    return (
      <json type="object">
        <test type="object">
          <type type="string">test</type>
          <test type="array">
            <item type="string">{$test}</item> <!-- testa and testb were undefined -->
            <item type="string">{$test}</item>
          </test>
        </test>
      </json>
    )
  }</json>
)

Among the issues this avoids:

  • You don't need to add syntactical commas at all -- they're completely generated by the transform-to-json call, mooting that entire set of issues.
  • Inadvertently malformed output (if your XML text node contains characters that need to be escaped to be valid in JSON -- this is true of newlines, for instance).
  • Injection attacks (if your $testa or $testb contains test", "hello", "world", "foo then you'd have extra separate elements in your JSON code; more aggressive attacks could escape the structure and add completely new dictionaries to your outer list).

Upvotes: 6

wst
wst

Reputation: 11771

Instead of detecting the last element and handling this within your loop, use string-join, which automatically does what you want:

string-join(
  for $row in /md:row
  let $test := $row/md:test/text()
  let $last := $row/*[fn:position() = fn:last()]
  return (
   '{
    "test": {
    "type": "test",
    "test": [',$testa,',',$testb,']
  },
", ")   

Upvotes: 2

Related Questions