Search code examples
jsonxquerymarklogicmarklogic-8

Transform XML elements of the same name into JSON properties of the same name


XML elements and JSON properties of the same name may be siblings. I.e.:

<container>
  <value>value1</value>
  <value>value2</value>
</container>

and

object-node {
  "value" : "value1",
  "value" : "value2"
}

are both valid, but I have not found a valid way to transform one into the other. It's invalid to dynamically build properties within an object-node constructor, i.e.:

object-node {
  for $v in $values
  return 'value' : $v
}

Using maps doesn't work because the duplicate key names are collapsed:

xdmp:to-json(map:new((
  map:entry("value", "value1"), 
  map:entry("value", "value2")))
  )

=> {"value":"value2"}

And when using json:object, the last key value is duplicated:

json:object(<json:object>
  <json:entry key="value">
    <json:value>value1</json:value>
  </json:entry>
  <json:entry key="value">
    <json:value>value2</json:value>
  </json:entry>
</json:object>)

=> {"value":"value2", "value":"value2"}

Joining maps using the + operator is better, but it merges the duplicate keys into a single key with an array of values ({"value":["value1", "value2"]}), which is still not what I want. Is there any way to build sibling JSON properties of the same name dynamically in XQuery?


Solution

  • Your JSON example:

    object-node {
      "value" : "value1",
      "value" : "value2"
    }
    

    isn't really valid: or at any rate, it's best avoided. RFC 7159 says:

    When the names within an object are not unique, the behavior of software that receives such an object is unpredictable. Many implementations report the last name/value pair only. Other implementations report an error or fail to parse the object, and some implementations report all of the name/value pairs, including duplicates.