#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.