xquery version '3.1';
(:~ save  conversion outputs to file 
ensures target folders created
save multiple docs when root <wrapper> found
optionally serialize XML with default namespace 
@author quodatum Andy Bunce
:)
module namespace outlet = 'urn:conversion:outlet';

(: serialization options
 key is arbitary name, value is BaseX serialization option map 
for xml serializations the non-standard 'ns' option supplies a namespace to use as default ' :)
declare variable $outlet:serial:=map{
  "xvrl":   map{"method":"xml","ns":"http://www.xproc.org/ns/xvrl"},
  "docbook":map{"method":"xml","ns":"http://docbook.org/ns/docbook"},
  "csv":    map{"method":"text"},
  "xml":    map{"method":"xml"}
};

(:~save $doc to $dest unless empty,will create directories as required 
@param $opts serialization options and ns to set a default namespace :)
declare function outlet:save($doc as item(),$dest as xs:string?,$opts as map(*)?)
as xs:string?{
  if (exists($dest))
  then 
     let $doc:=if($opts?ns)
               then outlet:change-element-ns-deep($doc,$opts?ns,"")
               else $doc
     return (
                file:create-dir(file:parent($dest)),
                file:write($dest,$doc,map:remove($opts,"ns")),
                $dest
            )
};

(:~ save file or files if node is wrapper
@return paths to saved files
:)
declare function outlet:save-wrapper($doc as item(),$dest as xs:string?,$opts as map(*)?)
as xs:string*{
 if ($doc/wrapper)
 then $doc/wrapper/result! outlet:save(*,file:resolve-path(@href,$dest),$opts)
 else outlet:save($doc,$dest,$opts) 
};

(:~ from functx http://www.xqueryfunctions.com/xq/functx_change-element-ns-deep.html :)
declare function outlet:change-element-ns-deep
  ( $nodes as node()* ,
    $newns as xs:string ,
    $prefix as xs:string )  as node()* {

  for $node in $nodes
  return if ($node instance of element())
         then (element
               {QName ($newns,
                          concat($prefix,
                                    if ($prefix = '')
                                    then ''
                                    else ':',
                                    local-name($node)))}
               {$node/@*,
                outlet:change-element-ns-deep($node/node(),
                                           $newns, $prefix)})
         else if ($node instance of document-node())
         then outlet:change-element-ns-deep($node/node(),
                                           $newns, $prefix)
         else $node
 } ;

(:~ @see https://stackoverflow.com/a/8600987/3210344 :)
 declare function outlet:remove-prefixes($node as node(), $prefixes as xs:string*) 
 as node(){
    typeswitch ($node)
    case element()
        return
            if ($prefixes = ('#all', prefix-from-QName(node-name($node)))) then
                element {QName(namespace-uri($node), local-name($node))} {
                    $node/@*,
                    $node/node()/outlet:remove-prefixes(., $prefixes)
                }
            else
                element {node-name($node)} {
                    $node/@*,
                    $node/node()/outlet:remove-prefixes(., $prefixes)
                }
    case document-node()
        return
            document {
                $node/node()/outlet:remove-prefixes(., $prefixes)
            }
    default
        return $node
};

(:~ relative file paths below folder $path, matching $selector :)
declare  function  outlet:select($path as xs:string,$selector as map(xs:string,item()*))
as xs:string*
{
file:list($path,true(),$selector?pattern)
[some $i in $selector?include satisfies contains(.,$i)]
[every $x in $selector?exclude satisfies not(contains(.,$x))]  
};