Преобразование элементов XML с тем же именем в свойства JSON с тем же именем

Элементы XML и свойства JSON с одним и тем же именем могут быть одноуровневыми. То есть:

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

а также

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

оба действительны, но я не нашел действительного способа преобразовать одно в другое. Недопустимо динамическое создание свойств в конструкторе object-node, т.е.:

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

Использование карт не работает, потому что повторяющиеся имена ключей свернуты:

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

=> {"value":"value2"}

А при использовании json:object дублируется последнее значение ключа:

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"}

Соединение карт с помощью оператора + лучше, но он объединяет повторяющиеся ключи в один ключ с массивом значений ({"value":["value1", "value2"]}), что все равно не то, что мне нужно. Есть ли способ динамически создавать родственные свойства JSON с тем же именем в XQuery?


person wst    schedule 01.12.2017    source источник
comment
Я согласен с Майклом Кеем и рекомендую избегать неуникальных имен свойств. Есть способы заставить его работать, но позже вы столкнетесь с побочными эффектами, такими как потенциальные трудности с обновлением документов JSON с неуникальными свойствами, когда-то сохраненными в базе данных MarkLogic.   -  person grtjn    schedule 03.12.2017
comment
@grtjn Да, я согласен, что это кажется правильным. Тем не менее, MarkLogic явно разрешает такое поведение, в то время как никто другой, похоже, этого не делает. Обработка повторяющихся имен свойств была бы удобна для того, чтобы преобразованные документы JSON были ближе по структуре к их XML-эквивалентам, но я буду работать над этим.   -  person wst    schedule 03.12.2017
comment
MarkLogic терпит это только потому, что не любит потери данных, но это не значит, что она не возражает. Как уже говорилось, вы можете сохранять JSON с неуникальными свойствами, но каждый раз, когда вы прикасаетесь к JSON, вы должны быть осторожны при обращении с ним. И хотя xdmp:unquote позволяет анализировать неуникальные свойства, xdmp:from-json-string этого не делает и выдает ошибку.   -  person grtjn    schedule 03.12.2017


Ответы (2)


Ваш пример JSON:

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

на самом деле недействителен: или, во всяком случае, его лучше избегать. RFC 7159 говорит:

Когда имена внутри объекта не уникальны, поведение программного обеспечения, получающего такой объект, непредсказуемо. Многие реализации сообщают только пару "фамилия/значение". Другие реализации сообщают об ошибке или не могут проанализировать объект, а некоторые реализации сообщают обо всех парах имя/значение, включая дубликаты.

person Michael Kay    schedule 02.12.2017
comment
Спасибо, Майкл. Мои предположения о том, что является действительным JSON, были основаны на том, что, по-видимому, является специфичным для MarkLogic поведением. Эквивалентные конструкторы JSON в FF, Safari, Chrome и eXist-db приводят к одному и тому же поведению: сообщают только о последней паре ключ/значение (Safari создает исключение в дополнение к созданию переменной). - person wst; 03.12.2017

Я не верю, что можно встроить FLWOR внутрь конструктора object-node().

Вы можете создать строку и выполнить оценку с помощью xdmp:eval() или xdmp:value():

let $container := 
    <container>
      <value>value1</value>
      <value>value2</value>
    </container>

return
  xdmp:value(
   "object-node {" || 
     fn:string-join($container/value ! ('"' || local-name() || '": "' || . || '"'), ",") || 
   " }"
  )

Или создайте строку JSON и используйте xdmp:unquote():

let $container := 
    <container>
      <value>value1</value>
      <value>value2</value>
    </container>

return
  xdmp:unquote(
   "{" || 
     fn:string-join($container/value ! ('"' || local-name() ||'": "' || . || '"'), ",") || 
   "}"
  )
person Mads Hansen    schedule 02.12.2017
comment
xdmp:eval работает медленно, xdmp:value будет быстрее. И если вы все равно создаете строку, рассмотрите возможность создания строки JSON и ее анализа с помощью xdmp:unquote. Я бы все же не рекомендовал неуникальные свойства.. :) - person grtjn; 03.12.2017