Generi c XQuery для рекурсивного обхода XML - PullRequest
1 голос
/ 17 февраля 2020

Я пытаюсь преобразовать входные данные XML, приведенные ниже, в формат вывода, используя generi c Xquery, без вызова каких-либо родительских / дочерних элементов. Если у родителя есть два или более повторяющихся потомка, то это должно быть сгруппировано как массив.

XML:

<root>
<name>xxx</name>
<id>1</id>
<tasks>
    <job>
        <id>1</id>
        <val>2</val>
    </job>
    <job>
        <id>2</id>
        <val>12</val>
    </job>
    <job>
        <id>3</id>
        <val>22</val>
    </job>
</tasks>
</root>

Ожидаемый результат:

<map>
<string key="name">xxx</string>
<string key="id">1</string>
<array key="tasks">
    <map key="job">
        <string key="id">1</string>
        <string key="val">2</string>
    </map>
    <map key="job">
        <string key="id">2</string>
        <string key="val">12</string>
    </map>
    <map key="job">
        <string key="id">3</string>
        <string key="val">22</string>
    </map>
</array>
</map>

XQuery Я пытался:

declare default element namespace "http://www.w3.org/2005/xpath-functions";
for $a in /*[1]
let $retval := 
<map>
    {
    for $z in $a//* 
    return if ($z/*/text()) then
    (
    <map>
        {
        for $zz in $z/child::* 
        return if ($zz/text()) then
        (
        <string key="{lower-case(name($zz))}">{data($zz)}</string>
        )
        else ()
        }</map>
    ) 
    else () 
    } 
</map> 
return $retval

Ответы [ 2 ]

2 голосов
/ 17 февраля 2020

Привет. Пожалуйста, проверьте прилагаемый код:

declare function local:testChild($in)
{
    if($in/text())
    then <string key="{local-name($in)}">{$in/node()}</string>
    else if(not($in/*/text()))
        then 
   <array key="{local-name($in)}">{for $in in $in/*
                return local:testChild($in)
                }</array>

    else <map key="{local-name($in)}">{for $in in $in/*
                return local:testChild($in)
                }</map>

};

let $markup:=<root>
<name>xxx</name>
<id>1</id>
<tasks>
    <job>
        <id>1</id>
        <val>2</val>
    </job>
    <job>
        <id>2</id>
        <val>12</val>
    </job>
    <job>
        <id>3</id>
        <val>22</val>
    </job>
</tasks>
</root>


let $first:=<map>{for $in in  $markup/*
    return local:testChild($in)
}</map>
return $first

См. Преобразование в https://xqueryfiddle.liberty-development.net/94hwphU

0 голосов
/ 19 февраля 2020

Вы можете попробовать это

declare function local:create_structure($child)
{
    for $input in $child
    return
        element {
            (if ($input/*/*) then
                'array'
            else
                if ($input/*) then
                    'map'
                else
                    'string')
        } {
            attribute {'key'} {local-name($input)},
            if ($input/*) then
                local:create_structure($input/*)
            else
                $input/node()
        }
};

let $Output := <map>{local:create_structure(/*)}</map>
return
    $Output

См. Преобразование в https://xqueryfiddle.liberty-development.net/bFDbxkW/1

...