Update name based refs xquery

For updating name based references to id based based references in a DECOR project or the entire server. Name based references used to be supported because when the editors when not that sophisticated a lot of hand editing was required. Name based references were a way to make the DECOR files friendlier. However: there is no guarantee that names are unique across projects and it quickly became clear they are ambiguous and have no future.

Note: once applied to your project, there is no undo unless you keep a copy of the project/all projects as backup.

This xquery will perform the following actions:

  • Lookup name based references to templates and valueSets
  • Lookup the target object and, if only 1 is found update the name based reference to an id based reference
  • If multiple are found, this is included in the final report for you to decide
  • The variable $execute which is false() by default allows you to first assess what the situation is before changing anything

To run the xquery below on the server:

  • Open a webbrowser, surf to: http://<server>:8877
  • Click on ‘dashboard’.
  • Log in as ‘admin’.
  • Open eXide.
  • Click: ‘New XQuery’ (paste the xquery in the box below to the browserscreen)
  • Click: ‘eval’ to run the xquery.
import module namespace get      = "http://art-decor.org/ns/art-decor-settings" at "xmldb:exist:///db/apps/art/modules/art-decor-settings.xqm";
import module namespace art      = "http://art-decor.org/ns/art" at "xmldb:exist:///db/apps/art/modules//art-decor.xqm";
import module namespace vs       = "http://art-decor.org/ns/decor/valueset" at "xmldb:exist:///db/apps/art/api/api-decor-valueset.xqm";
import module namespace templ    = "http://art-decor.org/ns/decor/template" at "xmldb:exist:///db/apps/art/api/api-decor-template.xqm";

(: set to true if you want name based references replaced with oid based references :)
declare variable $execute as xs:boolean  := false();

declare function local:replaceWithOidTemplate($el as element()) {
    let $prefix := $el/ancestor::decor/project/@prefix
    let $ref    := $el/(@contains|@ref|@template|@valueSet)
    let $flex   := if ($el/@flexibility) then $el/@flexibility else 'dynamic'
    let $obj    := templ:getTemplateByRef($ref, $flex, $prefix)/template/template[@id]
    let $upd1   := <current ref="{$ref}" flexibility="{$flex}"/>
    let $upd2   := 
        if (matches($ref,'^[0-9\.]+$') or count($obj) != 1) then (false()) else (
            let $update := if ($execute) then (update insert comment {concat($ref/name(),' name="',$ref,'"')} preceding $ref/parent::*) else ()
            let $update := if ($execute) then (update value $ref with $obj/@id) else ()
            return true()
        )
    (:let $upd3   :=
        if ($el/@flexibility='dynamic') then (
            let $ref := if ($execute) then (update delete $el/@flexibility) else ()
            return true()
        ) else (false()):)
    
    return
        element {name($el)} {
            attribute currentRef {$upd1/@ref},
            attribute currentFlex {$upd1/@flexibility},
            if ($upd2=false()) then () else (attribute newRef {$obj/@id}),
            (:if ($upd3=false()) then () else (attribute newFlex {'dynamic'}),:)
            <text>
            {
                (:if ($upd2=true() and $upd3=true()) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". New value: @', name($ref), '="',$obj/@id,'" and @flexibility="dynamic" has been removed.')
                else :)if ($upd2=true()) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". New value: @', name($ref), '="',string-join(distinct-values($obj/@id),' '),'"')
                (:else if ($upd3=true()) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". Attribute @flexibility="dynamic" has been removed.'):)
                else if (count($obj) > 1) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". However multiple objects were found (',count($obj),', so no change was applied.')
                else (
                    concat(name($el), ' element does not need any change')
                )
            }
            </text>
        }
};

declare function local:replaceWithOidValueSet($el as element()) {
    let $prefix := $el/ancestor::decor/project/@prefix
    let $ref    := $el/(@contains|@ref|@template|@valueSet)
    let $flex   := if ($el/@flexibility) then $el/@flexibility else 'dynamic'
    let $obj    := vs:getValueSetByRef($ref, $flex, $prefix)//valueSet[@id]
    let $upd1   := <current ref="{$ref}" flexibility="{$flex}"/>
    let $upd2   := 
        if (matches($ref,'^[0-9\.]+$') or count($obj) != 1) then (false()) else (
            let $update := if ($execute) then (update insert comment {concat($ref/name(),' name="',$ref,'"')} preceding $ref/parent::*) else ()
            let $update := if ($execute) then (update value $ref with $obj/@id) else ()
            return true()
        )
    (:let $upd3   :=
        if ($el/@flexibility='dynamic' and count($obj) = 1) then (
            let $ref := if ($execute) then (update delete $el/@flexibility) else ()
            return true()
        ) else (false()):)
    
    return
        element {name($el)} {
            attribute currentRef {$upd1/@ref},
            attribute currentFlex {$upd1/@flexibility},
            if ($upd2=false()) then () else (attribute newRef {$obj/@id}),
            (:if ($upd3=false()) then () else (attribute newFlex {'dynamic'}),:)
            <text>
            {
                (:if ($upd2=true() and $upd3=true()) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". New value: @', name($ref), '="',$obj/@id,'" and @flexibility="dynamic" has been removed.')
                else :)if ($upd2=true()) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". New value: @', name($ref), '="',string-join(distinct-values($obj/@id),' '),'"')
                (:else if ($upd3=true()) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". Attribute @flexibility="dynamic" has been removed.'):)
                else if (count($obj) > 1) then
                    concat(name($el), ' element currently has @', name($ref), '="',$ref,'" and @flexibility="',$flex,'". However multiple objects were found (',count($obj),', so no change was applied.')
                else (
                    concat(name($el), ' element does not need any change')
                )
            }
            </text>
        }
};

let $projectPrefix  := 'demo1-'
let $decors         := 
    if (empty($projectPrefix)) 
    then $get:colDecorData//decor 
    else $get:colDecorData//decor[project/@prefix=$projectPrefix]

return
    <x execute="{$execute}">
    {
        for $ref in ( $decors//*[@valueSet] )
        return
            local:replaceWithOidValueSet($ref)
        ,
        for $ref in ( $decors//transaction/representingTemplate[@ref] | 
                      $decors//relationship[@ref][parent::template][not(ancestor::example)] | 
                      $decors//element[@contains][ancestor::template][not(ancestor::example)] | 
                      $decors//include[@ref][ancestor::template][not(ancestor::example)] 
                    )
        return
            local:replaceWithOidTemplate($ref)
    }
    </x>