MarkLogic json: преобразование из json с несколькими пространствами имен?

#json #xquery #marklogic

#json #xquery #marklogic

Вопрос:

В MarkLogic можно ли использовать json:transform-from-json для преобразования json в XML с несколькими пространствами имен? Например, как преобразовать

 {
  options: {
    format: "xml"
  }
}
 

в

 <options xmlns="xdmp:http-get">
  <format xmlns="xdmp:document-get">xml</format>
</options>
 

Ответ №1:

В примере JSON нет ничего, что указывало бы, что эти пространства имен должны применяться к элементам XML.

При использовании json:transform-from-json() результирующий XML будет находиться в http://marklogic.com/xdmp/json/basic пространстве имен.

 <json type="object" xmlns="http://marklogic.com/xdmp/json/basic">
  <options type="object">
    <format type="string">xml</format>
  </options>
</json>
 

Затем вам нужно будет преобразовать этот XML, чтобы получить эти элементы в желаемых пространствах имен. Один из способов сделать это — использовать рекурсивную функцию переключения типов:

 xquery version "1.0-ml";
declare namespace j = "http://marklogic.com/xdmp/json/basic";
import module namespace json="http://marklogic.com/xdmp/json"
 at "/MarkLogic/json/json.xqy";

declare function local:convert($node as node()) as item()* {
  typeswitch($node)
    case attribute() return ()
    case element(j:json) return local:convert($node/node())
    case element(j:options) return element {fn:QName("xdmp:http-get", $node/local-name())} {local:convert($node/node())}
    case element() return element {fn:QName("xdmp:document-get", $node/local-name())} {local:convert($node/node())}
    default return $node
};

let $json := '{
  options: {
    format: "xml"
  }
}'

return local:convert(json:transform-from-json( $json ))
 

Однако, если вы пытаетесь создать XML для создания параметров xdmp:document-get() , возможно, вам проще указать параметры, используя a map:map вместо формы XML.

Параметры, с помощью которых можно настроить эту операцию. Вы можете указать параметры либо как элемент XML в пространстве имен «xdmp: document-get», либо как map:map . Имена параметров, приведенные ниже, являются локальными именами элементов XML. При использовании карты замените дефисы на верблюжью оболочку. Например, «an-option» становится «anOption» при использовании в качестве ключа map:map.

Если у вас есть объект JSON, вы можете выбрать options свойство, а затем использовать fn:data() или xdmp:from-json() для атомизации options объекта-узла в качестве карты:

 fn:data($json//options)
 

Комментарии:

1. Спасибо за ваше предложение по использованию map: map. Это действительно гораздо более простой путь.

Ответ №2:

Да, вы можете, это не задокументировано или просто, но это не секрет. Посмотрите на исходный код в Modules/MarkLogic/json/custom.xqy

Существует еще много пользовательских параметров, которые затем документируются. «Интересные» из них позволяют вам переопределять отдельные методы, используемые для преобразования. Пример: при использовании пользовательской стратегии вы можете установить переопределения. Ниже приведены значения по умолчанию, их можно изменить.

 map:put($c , $json-custom:element-qname-from-json-name  , json-custom:element-qname-from-json-name#2 ),
map:put($c , $json-custom:attribute-qname-from-json-name  , json-custom:attribute-qname-from-json-name#2 ),
 

Замените функцию ‘json-custom:element-qname-from-json-name’ на свою собственную — вы можете использовать любую логику, которую хотите, учитывая объект конфигурации и текущее имя поля json, возвращая полное QName.

Встроенную функцию вы можете извлечь из приведенного выше файла (она не скрыта). Начиная с версии 9.0 это выглядит так:

 declare %private function json-custom:element-qname-from-json-name( $config as map:map , $json_name as xs:string? ) as xs:QName
{

   json-custom:qname( map:get( $config , $json-custom:element-namespace ) ,
                      map:get( $config , $json-custom:element-namespace-prefix ) ,
                      if(map:get($config , $json-custom:camel-case)) then  json-custom:from-camelCase($json_name) else $

 };
 

Это может быть очень сложно сделать правильно. Я рекомендую комбинацию пользовательских преобразований с последующей последующей обработкой xml (с использованием xquery или xslt).

Сложность заключается в том, что вы не получаете большого «контекста» при переходе от JSON к XML. JSON не имеет предков узлов или упорядочения. Все, что вы получаете, — это одно имя поля. Если вы можете сопоставить это с нужным QName, то это просто. Например, вы можете создать сопоставление имен json с QNames и поместить это в конфигурацию вместе с вашей пользовательской функцией.

Часто требования более сложные, поэтому рекомендуется просто попытаться «приблизиться» к конфигурации, а затем опубликовать процесс.

Комментарии:

1. Спасибо! Я ценю вашу ценную информацию для MarkLogic internals.